Skip to the solution
EasyMachine Coding9 min read

Build a Segmented Control

938 views

The problem

Question presented to candidate: "Build a segmented control, the pill-shaped row of options you see in a calendar for Day / Week / Month. Exactly one option is selected, a highlight slides to it when the selection changes, and the parent page owns the value. It must work with the keyboard and announce correctly to screen readers."

Requirements:

  • Props: an options array (value, label), the current value, an onChange callback (or two-way binding in Vue and Angular) and a label for the group.
  • Fully controlled: the component never changes its own selection; when the parent changes value (for example a "Reset" button), the control follows.
  • Semantics of a single-choice group: role="radiogroup" with an accessible name, each option role="radio" with aria-checked.
  • Roving tabindex: only the selected option is in the Tab order. Arrow Right / Down select the next option, Arrow Left / Up the previous, both wrapping; Home and End select the first and last.
  • A single indicator element slides under the selected option with a CSS transition, disabled for reduced motion. Several controls on one page work independently.

What a strong answer should cover:

  • Controlled versus uncontrolled components, and deriving the selected index from value instead of storing it.
  • Why this is a radio group (a choice of value), not a tab list (which switches panels), and what that changes in roles.
  • Roving tabindex, and moving focus together with selection.
  • Animating the indicator: equal-width segments allow a pure translateX(index * 100%); unequal widths require measuring with layout APIs.
  • Reduced-motion support and readable behaviour at narrow widths.

Clarifying questions expected:

  • "Are all segments the same width, or do they size to their labels?"
  • "Can an option be disabled?"
  • "Should arrow keys select immediately, or only move focus?"

Code / implementation expected: Yes. A reusable controlled component and a demo with two instances and a parent-side reset.

  • React
  • UI
  • State

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

9 min read ยท 9 sections

React solution

Every file of the working solution. Open it in the playground to run and change it.

ReactComplete solution
import { useState } from "react";
import SegmentedControl from "./src/components/SegmentedControl";

const VIEWS = [
  { value: "day", label: "Day" },
  { value: "week", label: "Week" },
  { value: "month", label: "Month" },
];
const DENSITY = [
  { value: "compact", label: "Compact" },
  { value: "comfortable", label: "Comfortable" },
];

export default function App() {
  // The parent owns the value: the control is fully controlled.
  const [view, setView] = useState("week");
  const [density, setDensity] = useState("comfortable");

  return (
    <main className="page">
      <h1>Calendar</h1>
      <div className="row">
        <SegmentedControl
          label="Calendar view"
          options={VIEWS}
          value={view}
          onChange={setView}
        />
        <button type="button" className="reset" onClick={() => setView("week")}>
          Reset to Week
        </button>
      </div>
      <div className="row">
        <SegmentedControl
          label="Row density"
          options={DENSITY}
          value={density}
          onChange={setDensity}
        />
      </div>
      <p className="readout" data-testid="readout">
        Showing the {view} view, {density} rows.
      </p>
    </main>
  );
}

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 12 of 107 in Machine coding

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

Up nextEasy

Build a Tabs component

Continue