Skip to the solution
MediumMachine Coding12 min read

Build a Tag / Chip Input

812 views

The problem

Question presented to candidate: "Our post editor needs a topics field. Users type a topic and press Enter or a comma to turn it into a chip; each chip has a remove button; Backspace in the empty box removes the last chip. No duplicates, at most five topics. Build it as a reusable component whose parent receives the list."

Requirements:

  • Enter or a comma turns the typed text into a chip. Text is trimmed and inner spaces collapsed; empty text is ignored.
  • Pasting "a, b, c" adds several chips at once; text after the last comma stays in the box.
  • Duplicates are rejected case-insensitively, tags longer than 20 characters are rejected, and at most 5 tags are allowed. Each rejection is explained.
  • Each chip has an accessible remove button; after removing, focus returns to the text box.
  • Backspace in an empty box first highlights the last chip, and a second Backspace removes it.
  • Clicking anywhere in the field focuses the text box. The parent owns the array of tags.
  • Messages ("Added vue", "vue is already added") are announced to screen readers.

What a strong answer should cover:

  • The state split: the tag array (owned by the parent, controlled) versus the draft text, the armed flag and the message (local).
  • A pure addParts helper that validates and returns the next list plus a message, which makes the rules easy to test.
  • Handling commas in the input event, not keydown, so paste and mobile keyboards work; Enter in keydown with an IME composition guard.
  • Focus management after removal, and a live region for announcements.
  • Stable keys for the chips (the tag text, since tags are unique).

Clarifying questions expected:

  • "Are tags case-sensitive? Should 'React' and 'react' count as the same?"
  • "Free text, or only tags from a suggestion list?"
  • "What separators besides Enter and comma: Tab, space, semicolon?"

Code / implementation expected: Yes. A working component with add, dedupe, limits, remove by button and Backspace, paste splitting and announcements.

  • React
  • Input
  • Chips

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

12 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 TagInput from "./src/components/TagInput";

export default function App() {
  const [tags, setTags] = useState(["react"]); // the parent owns the list

  return (
    <main className="page">
      <section className="card">
        <h1>New post</h1>
        <TagInput value={tags} onChange={setTags} max={5} label="Topics" />
        <pre className="out" data-testid="tags-json">
          {JSON.stringify(tags)}
        </pre>
      </section>
    </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 40 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 nextMedium

Build a debounced Search Bar

Continue