AniUI Academy

Build a tag input

mediumUI Components+190 XP

Build an input that turns whatever you type into a removable tag when you press Enter.

Pressing Backspace while the input is empty removes the most recently added tag, rather than doing nothing.

Examples

// Type "react", press Enter   → tags: ["react"],         input cleared.
// Type "typescript", Enter      → tags: ["react","typescript"].
// Backspace on empty input      → tags: ["react"].
// Click × on "react"            → tags: [].

Backspace-on-empty is the keyboard shortcut everyone expects but no one implements.

function handleKeyDown(e) {
  if (e.key === "Enter") {
    const trimmed = value.trim();
    if (trimmed) {
      setTags((current) => [...current, trimmed]);
      setValue("");
    }
  } else if (e.key === "Backspace" && value === "" && tags.length) {
    setTags((current) => current.slice(0, -1));
  }
}

Trim before pushing; the empty check prevents stray whitespace tags.

What it has to do

  • A `<input id="tag-input">` for typing new tags.
  • Each tag renders as `<span data-testid="tag">text</span>` inside a container `data-testid="tag-list"`, in the order added.
  • Pressing Enter with non-empty input text adds it as a new tag and clears the input.
  • Pressing Enter with only whitespace, or an empty input, adds nothing.
  • Each tag has a `<button data-testid="remove-tag">` that removes just that tag.
  • Pressing Backspace while the input is empty removes the last tag in the list.

Notes

  • Preventing default on Enter inside a `<form>` matters — otherwise the form submits. Not required by the test, but every real tag input lives inside one.
  • Consider deduplicating case-insensitively on insert — the spec doesn't test it, but email/skills fields almost always want it.
  • Backspace on empty must only pop; don't also prevent default or the browser's own text-navigation behaviour breaks when the input isn't empty.
  • For accessibility, each chip should expose the remove button with an `aria-label` like "Remove react" — screen readers hearing just "×" don't know what's being removed.
Asked atAtlassianLinkedInShopify

Stuck? The react course covers the ideas this problem is built on.

import { useState } from "react";

export default function App() {
  const [tags, setTags] = useState([]);
  const [value, setValue] = useState("");

  function handleKeyDown(e) {
    // TODO: Enter with non-empty (non-whitespace-only) text adds a tag
    // and clears the input. Backspace with an empty input removes the
    // last tag.
  }

  function removeTag(index) {
    setTags((current) => current.filter((_, i) => i !== index));
  }

  return (
    <div style={{ fontFamily: "sans-serif", padding: 16 }}>
      <div
        data-testid="tag-list"
        style={{ display: "flex", flexWrap: "wrap", gap: 6, marginBottom: 8 }}
      >
        {tags.map((tag, index) => (
          <span
            key={index}
            data-testid="tag"
            style={{ background: "#eee", padding: "4px 8px", borderRadius: 12 }}
          >
            {tag}
            <button
              data-testid="remove-tag"
              onClick={() => removeTag(index)}
              style={{ marginLeft: 6 }}
            >
              &times;
            </button>
          </span>
        ))}
      </div>
      <input
        id="tag-input"
        value={value}
        onChange={(e) => setValue(e.target.value)}
        onKeyDown={handleKeyDown}
        placeholder="Type and press Enter..."
        style={{ padding: 8, width: "100%", boxSizing: "border-box" }}
      />
    </div>
  );
}

5 tests · +190 XP

Discussion

Sign in to post
Sign in to join the conversation.Sign in

No comments yet. Be the first to say something.