Lesson overview · Free interview practice

Frontend Interviews

For a local UI attempt, open Build a Local Autocomplete. Its preparation, starter and feedback are free. The other questions provide format, design, utility and communication references.

Practice common frontend interview questions.

Topics in the full lesson
  • Frontend interview formats
  • Clarify the requested behavior
  • Turn requirements into state and checks
  • Choose the preparation you need
  • Reason about the local list's work
  • Communicate and debug during the attempt
  • Prepare the local UI rehearsal
  • Evaluate behavior and explain choices
  • Practice checkpoints

Practice Problems

Work through a question before revealing its explanation. These questions and answers are free; Premium adds the full lesson walkthrough, examples and implementation detail.

Completion marks record your own progress, not an automatically checked result. The task type does not determine whether it is optional.

TheoryEasy

Frontend Behavioral Questions: The Three Story Types

Question

What are the frontend-specific behavioral story types, and how do you structure them with STAR?

Take a moment to think about this before revealing the answer

Explain your reasoning or try an implementation before comparing answers.

TheoryMedium

Live-Coding a React Component: What Interviewers Watch For

Question

In a React live-coding round, what do interviewers look for, and what gets you dinged?

Take a moment to think about this before revealing the answer

Explain your reasoning or try an implementation before comparing answers.

TheoryMedium

The Five Frontend Interview Formats

Question

What are the five formats of a modern frontend interview, and what does each one test for?

Take a moment to think about this before revealing the answer

Explain your reasoning or try an implementation before comparing answers.

TheoryMedium

JavaScript Implementation Challenges Catalog

Question

What are the canonical JS implementation challenges interviewers ask, and what is the reference implementation for each?

Take a moment to think about this before revealing the answer

Explain your reasoning or try an implementation before comparing answers.

TheoryHard

Frontend System Design: The 6-Step Framework

Question

What is the canonical framework for a frontend system-design interview, and how do you apply it?

Take a moment to think about this before revealing the answer

Explain your reasoning or try an implementation before comparing answers.

CodingHard

Build a Local Autocomplete

Implement and check your solution in the stated environment before revealing the answer.

Question

Build a React autocomplete for a preloaded list. Users can type to filter, move through matches with the keyboard and commit one option with Enter or a pointer. Keep draft text separate from the committed choice.

Use the requirements below. Explain the state you store and demonstrate the important transitions. Work locally in JavaScript or TypeScript. This is a free coding task, not an in-site editor or automatic judge. You don't need a backend, payment account or email service.

The component boundary

Implement Autocomplete with three props:

PropContract
labelA nonempty visible label for the text input
optionsAn immutable array of 0 to 100 original option objects. Each object has a unique nonempty opaque string id and a label
onSelectionChangeReceive the exact original option object on each explicit commit. Receive null once when a real text change invalidates an existing commitment

Labels are nonempty, unique case-sensitively and at most 80 printable ASCII characters, U+0020 through U+007E. Spaces count. Alpha and alpha can both appear. An ID is data, not a selector or a label.

The component owns its draft text, open state, active option and commitment. Don't add a controlled selected-value prop or a reset API. Options won't change during a mount. The fixture reloads the page to try another array.

Filter with JavaScript's option.label.toLowerCase().includes(query.toLowerCase()). Keep source order. An empty query matches everything. Don't trim spaces, remove accents or add fuzzy matching. The input must retain Unicode and temporary IME text even though the supplied labels are ASCII.

Required behavior

The active option is the keyboard highlight. The committed option is the application's explicit choice. Typing and highlighting are not commits.

Event or stateWhat should happen
Initial mountEmpty text, no highlight or commitment and no visible results/status. No autofocus or callback
Focus or click the inputOpen matches without choosing a highlight. Show status instead if there are no matches
Actual text changeKeep the new text, open results/status and clear the highlight. Invalidate a previous commitment with one null callback. Further edits while uncommitted emit no more null callbacks
Down with no highlightOpen results and highlight the first match. With no matches, keep the highlight absent
Up with no highlightOpen results and highlight the last match
Further plain Up or DownMove one visible option and clamp at each end. Don't wrap or move the text caret
Plain Enter with an active visible optionCommit that original object once, copy its label into the input, close results/status and clear the highlight
Enter without an active visible optionDo nothing. Typing an exact label is not an implicit commit
Explicitly commit the same option againNotify once again, even if its ID is still the committed ID
Pointer activation of an optionCommit once, keep or return input focus and stay closed after focus returns
Pointer drag, cancel or touch scrollDon't commit. Touch scrolling must still work. Don't unmount a genuine click target before its activation
Escape, open or closedClose results/status and clear the highlight. Preserve the text and any valid commitment
Reopen after Escape or commitInput click or Up/Down must work without a blur/refocus round trip
Tab or Shift+TabClose without committing and allow native traversal. Options must not be extra Tab stops
Blur outside the widgetClose without committing. Account for pointer activation before dismissing its target
Home, End, Left or RightClear the highlight and preserve native caret/selection behavior
Modifiers and editing shortcutsPreserve copy, paste, selection, Backspace/Delete and platform shortcuts. Don't interpret modified arrows, Enter or Escape as plain commands
Mere highlight or dismissalNo callback

IME ownership comes first. Don't handle the IME's Up/Down candidate movement, Enter confirmation or Escape dismissal as combobox commands. Actual composition text changes still follow the normal text-change path. A composition boundary can put a keydown outside isComposing, including a key-code-229 event. Test the browser/OS/IME sequences you can observe. Don't assume a timer or one flag proves every IME works.

When results are requested, show No options available for an empty source array or No results for a nonempty array with no matches. These are nonselectable status messages, not fake options. Hide them on dismissal. While only status text is visible, aria-expanded must be false.

Accessibility and layout

  • Use a visible native label and a text input with combobox semantics and list autocomplete. Keep expanded state and its listbox relationship truthful.
  • Keep DOM focus on the input during keyboard navigation. Set aria-activedescendant only to the active visible option. The option's aria-selected describes popup selection, not the separate committed application value.
  • Give each instance its own input, listbox and option DOM IDs. Don't construct selectors from opaque data IDs. Render options with stable data keys.
  • Keep surrounding buttons reachable with Tab and Shift+Tab. No focus trap or option Tab stops.
  • Show input focus and active-option styling without relying on hover or color alone. Keep those indicators visible in forced colors.
  • At 320 CSS pixels, keep a readable single column. Wrap long labels, including unbroken ones. The list may scroll vertically but must not clip against a container or widen the page.
  • Scroll an active option into its list's visible area without gratuitously moving the whole page. No animation is needed.

This is one local input, not remote search. Don't add fetch, persistence, debounce, a portal, virtualization, multiselect, an extra dropdown button or a global-state library. There is no dynamic-options or form-submission contract.

Traces to try

The starter's first array is Alpha, Alpine, Beta and Alphabet, in that order.

TraceExpected result
Focus, type ALAlpha, Alpine and Alphabet. No highlight or commitment
Down, Down, EnterCommit the original Alpine object once. Input becomes Alpine and results close
Click input, EscapeKeep committed Alpine without another callback
Edit to Alpin, then AlpiOne null callback on the first edit, none on the next
Type exact Beta, then Enter without an arrowNo commitment
Type zzNo results, no active descendant and no selectable row
In the changed fixture, type a, Down, Down, then replace the text with dBoth filters have two matches. The old highlight must still clear and Enter must commit nothing
Open a list, Tab, Shift+TabReach the real surrounding controls without an implicit choice

Free readiness and return point

Before building the widget, make sure you can use a labeled controlled input, update visible text and render a list with stable ID keys. The complete Readiness file below provides that smaller exercise. It appears underneath the two unfinished widgets when the starter runs.

Type a word in Practice text and check that Visible text changes. Explain why the input has both value and onChange, why the label points to its ID and why each list item uses an option ID as its key. Resize to 320 pixels.

Return to the autocomplete when you can change that small example and explain what updated. It does not implement filtering or selection for you. If the readiness step is unfamiliar, spend time there first rather than treating setup as part of the HARD challenge.

Complete local starter

Choose one language and copy the matching files below. JS uses .jsx/.js. TS uses .tsx/.ts. Shared files have one pane. Don't mix the two entry HTML files or copy both tsconfig.json alternatives.

The starter intentionally renders Unfinished and reports zero callbacks. The supplied Autocomplete only edits draft text. Its accessible combobox behavior, filtering and selection are your work. The host and readiness capsule are already wired up.

Use Node 24.21.0 and npm 11.19.0, the versions used for this rehearsal. These projects pin React and React DOM 18.3.1, Vite 7.3.6, TypeScript 5.9.2 and the React type packages shown in the manifest. Vite 7.3 was in its important-fix/security-backport range when checked. This is a deliberately small client-only exercise, not a recommendation to copy Memoized's application dependencies or a claim that these versions are the newest.

The complete lockfile is included as one shared file. It pins transitive dependencies and registry integrity hashes as well as the direct versions. Its package records are compact to keep the copy panel manageable. You don't need to study them to solve the task.

Create a new directory with a src subdirectory. Save every matching file before installing. From that new project directory:

npm ci --ignore-scripts
npm run typecheck
npm run build
npm run dev -- --port 3030

Open the loopback address printed by Vite. Use port 3031 for a second project. --strictPort reports a collision instead of silently choosing another port. Stop the process with Ctrl+C. To inspect the built output after stopping the dev server, run npm run preview -- --port 3030.

In TS, typecheck checks the source under strict. In JS, it checks syntax and module resolution with checkJs: false. That JS command does not establish type safety. Neither a build nor a typecheck verifies the interaction contract.

Installation needs access to the public npm registry, or an approved registry mirror that preserves package integrity. Running the exercise only needs loopback assets. It does not call a mock endpoint or backend. Don't disable TLS or integrity checking to resolve an installation error.

Open the complete starter files

File: package.json

{
  "name": "local-autocomplete",
  "version": "1.0.0",
  "private": true,
  "type": "module",
  "engines": {
    "node": "^24.21.0"
  },
  "scripts": {
    "dev": "vite --host 127.0.0.1 --strictPort",
    "build": "vite build",
    "typecheck": "tsc --noEmit",
    "preview": "vite preview --host 127.0.0.1 --strictPort"
  },
  "dependencies": {
    "react": "18.3.1",
    "react-dom": "18.3.1"
  },
  "devDependencies": {
    "@types/react": "18.3.23",
    "@types/react-dom": "18.3.7",
    "typescript": "5.9.2",
    "vite": "7.3.6"
  }
}

JS file: tsconfig.json

{
  "compilerOptions": {
    "target": "ES2022",
    "lib": [
      "ES2022",
      "DOM",
      "DOM.Iterable"
    ],
    "module": "ESNext",
    "moduleResolution": "Bundler",
    "jsx": "react-jsx",
    "strict": false,
    "noEmit": true,
    "skipLibCheck": true,
    "allowImportingTsExtensions": true,
    "allowJs": true,
    "checkJs": false
  },
  "include": [
    "src"
  ]
}

JS file: index.html

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="color-scheme" content="light" />
    <title>Build a Local Autocomplete</title>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.jsx"></script>
  </body>
</html>

TS file: tsconfig.json

{
  "compilerOptions": {
    "target": "ES2022",
    "lib": [
      "ES2022",
      "DOM",
      "DOM.Iterable"
    ],
    "module": "ESNext",
    "moduleResolution": "Bundler",
    "jsx": "react-jsx",
    "strict": true,
    "noEmit": true,
    "skipLibCheck": true,
    "allowImportingTsExtensions": true
  },
  "include": [
    "src"
  ]
}

TS file: index.html

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="color-scheme" content="light" />
    <title>Build a Local Autocomplete</title>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.tsx"></script>
  </body>
</html>

File: src/main.jsx / src/main.tsx

import React from "react";
import { createRoot } from "react-dom/client";
import App from "./App";
import "./styles.css";
const root = document.getElementById("root");
if (!root) throw new Error("Missing #root in index.html");
createRoot(root).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
);

File: src/options.js / src/options.ts

function freeze(options) {
  return Object.freeze(options.map((option) => Object.freeze(option)));
}
export const demoOptions = freeze([
  { id: "alpha", label: "Alpha" },
  { id: "alpine", label: "Alpine" },
  { id: "beta", label: "Beta" },
  { id: "alphabet", label: "Alphabet" },
]);
export const changedOptions = freeze([
  { id: 'a # ["]', label: "ab" },
  { id: "b/opaque", label: "ac" },
  { id: ":c:", label: "bd" },
  { id: "d space", label: "cd" },
]);
export const transferOptions = freeze([
  { id: "upper", label: "Alpha" },
  { id: "lower", label: "alpha" },
  { id: "space", label: " " },
  { id: "padded", label: " Alpha " },
  { id: "long", label: "Long label ".repeat(7) + "end" },
  { id: "unbroken", label: "W".repeat(80) },
]);
export const hundredOptions = freeze(
  Array.from({ length: 100 }, (_, index) => ({
    id: `opaque #${index} ["]`,
    label: `Option ${String(index + 1).padStart(3, "0")} ` + "wide label ".repeat(5),
  })),
);
export const emptyOptions = freeze([]);

File: src/Readiness.jsx / src/Readiness.tsx

import React, { useId, useState } from "react";
import { demoOptions } from "./options";
export default function Readiness() {
  const id = useId();
  const [text, setText] = useState("");
  return (
    <section className="panel">
      <h2>Readiness: input and a list</h2>
      <label htmlFor={id}>Practice text</label>
      <input
        id={id}
        value={text}
        onChange={(event) => setText(event.currentTarget.value)}
      />
      <p>
        Visible text: <strong>{text || "(empty)"}</strong>
      </p>
      <ul>
        {demoOptions.map((option) => (
          <li key={option.id}>{option.label}</li>
        ))}
      </ul>
      <p>
        This list does not filter. Explain value, onChange and key, then return to the
        autocomplete.
      </p>
    </section>
  );
}

File: src/App.jsx / src/App.tsx

import React, { useState } from "react";
import Autocomplete from "./Autocomplete";
import Readiness from "./Readiness";
import {
  changedOptions,
  demoOptions,
  emptyOptions,
  hundredOptions,
  transferOptions,
} from "./options";
const fixture = new URLSearchParams(window.location.search).get("fixture");
const firstOptions =
  fixture === "empty"
    ? emptyOptions
    : fixture === "hundred"
      ? hundredOptions
      : fixture === "changed"
        ? changedOptions
        : fixture === "transfer"
          ? transferOptions
          : demoOptions;
function Example({ label, options }) {
  const [choice, setChoice] = useState(null);
  const [events, setEvents] = useState([]);
  function selectionChanged(option) {
    setChoice(option);
    const identity = option === null || options.some((original) => original === option);
    setEvents((previous) => [
      ...previous,
      `${option ? JSON.stringify(option) : "null"} | original object: ${identity}`,
    ]);
  }
  return (
    <section className="panel" aria-label={`${label} example`}>
      <Autocomplete
        label={label}
        options={options}
        onSelectionChange={selectionChanged}
      />
      <p>
        Committed:{" "}
        <output>{choice ? `${choice.label} (${choice.id})` : "No choice"}</output>
      </p>
      <p>
        Callback count: <span className="count">{events.length}</span>
      </p>
      <ol className="event-log" aria-label={`${label} callback log`}>
        {events.map((event, index) => (
          <li key={index}>{event}</li>
        ))}
      </ol>
    </section>
  );
}
export default function App() {
  return (
    <main>
      <h1>Build a Local Autocomplete</h1>
      <p>Local React rehearsal. No backend, automatic judge or form submission.</p>
      <p>
        Reload with ?fixture=empty, ?fixture=hundred, ?fixture=changed or
        ?fixture=transfer to change the first list. Each reload starts fresh.
      </p>
      <button type="button">Before widgets</button>
      <Example label="First choice" options={firstOptions} />
      <button type="button">Between widgets</button>
      <Example label="Second choice" options={transferOptions} />
      <button type="button">After widgets</button>
      <Readiness />
    </main>
  );
}

File: src/Autocomplete.jsx / src/Autocomplete.tsx

import React, { useId, useState } from "react";
export default function Autocomplete({ label, options, onSelectionChange }) {
  const id = useId();
  const [query, setQuery] = useState("");
  void onSelectionChange;
  return (
    <div className="autocomplete">
      <label htmlFor={id}>{label}</label>
      <input
        id={id}
        type="text"
        value={query}
        autoComplete="off"
        onChange={(event) => setQuery(event.currentTarget.value)}
      />
      <p className="status">
        Unfinished: {options.length} options supplied. Filtering, selection, keyboard
        behavior and combobox semantics are yours to build.
      </p>
      <p>Draft text: {query || "(empty)"}</p>
    </div>
  );
}

File: src/styles.css

:root {
  font-family: system-ui, sans-serif;
  color: #192b35;
  background: #f2f5f7;
  line-height: 1.5;
}
* { box-sizing: border-box; }
body { margin: 0; }
main { width: min(100%, 42rem); margin: auto; padding: 1rem; }
h1 { font-size: 1.8rem; line-height: 1.2; }
h2 { font-size: 1.25rem; }
p, li, output { overflow-wrap: anywhere; white-space: pre-wrap; }
button, input { font: inherit; min-height: 2.75rem; }
button { padding: .5rem .75rem; color: inherit; background: white; border: 2px solid #526675; }
input { width: 100%; min-width: 0; padding: .5rem; border: 2px solid #526675; border-radius: .25rem; }
label { display: block; font-weight: 700; margin-bottom: .35rem; }
input:focus, button:focus-visible { outline: 3px solid #005fcc; outline-offset: 3px; }
.panel { background: white; border: 1px solid #8c9ca8; padding: 1rem; margin: 1rem 0; min-width: 0; }
.autocomplete { min-width: 0; }
.results {
  list-style: none;
  margin: .5rem 0 0;
  padding: 0;
  border: 2px solid #526675;
  max-height: 14rem;
  overflow-y: auto;
  overscroll-behavior: contain;
  touch-action: pan-y;
}
.results li { padding: .65rem; border: 2px solid transparent; cursor: pointer; user-select: none; }
.results li[aria-selected="true"] {
  background: #e4efff;
  color: #102e52;
  border-color: #005fcc;
  font-weight: 700;
}
.status { padding: .65rem; background: #edf1f3; }
.event-log { font-size: .85rem; padding-left: 1.25rem; }
@media (forced-colors: active) {
  input:focus, button:focus-visible { outline-color: Highlight; }
  .results li[aria-selected="true"] { border-color: Highlight; outline: 1px solid Highlight; outline-offset: -4px; }
}

File: package-lock.json

{
  "name": "local-autocomplete",
  "version": "1.0.0",
  "lockfileVersion": 3,
  "requires": true,
  "packages": {
    "": {"name":"local-autocomplete","version":"1.0.0","dependencies":{"react":"18.3.1","react-dom":"18.3.1"},"devDependencies":{"@types/react":"18.3.23","@types/react-dom":"18.3.7","typescript":"5.9.2","vite":"7.3.6"},"engines":{"node":"^24.21.0"}},
    "node_modules/@esbuild/aix-ppc64": {"version":"0.28.2","resolved":"https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz","integrity":"sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==","cpu":["ppc64"],"dev":true,"license":"MIT","optional":true,"os":["aix"],"engines":{"node":">=18"}},
    "node_modules/@esbuild/android-arm": {"version":"0.28.2","resolved":"https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.2.tgz","integrity":"sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==","cpu":["arm"],"dev":true,"license":"MIT","optional":true,"os":["android"],"engines":{"node":">=18"}},
    "node_modules/@esbuild/android-arm64": {"version":"0.28.2","resolved":"https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz","integrity":"sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==","cpu":["arm64"],"dev":true,"license":"MIT","optional":true,"os":["android"],"engines":{"node":">=18"}},
    "node_modules/@esbuild/android-x64": {"version":"0.28.2","resolved":"https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.2.tgz","integrity":"sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==","cpu":["x64"],"dev":true,"license":"MIT","optional":true,"os":["android"],"engines":{"node":">=18"}},
    "node_modules/@esbuild/darwin-arm64": {"version":"0.28.2","resolved":"https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz","integrity":"sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==","cpu":["arm64"],"dev":true,"license":"MIT","optional":true,"os":["darwin"],"engines":{"node":">=18"}},
    "node_modules/@esbuild/darwin-x64": {"version":"0.28.2","resolved":"https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz","integrity":"sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==","cpu":["x64"],"dev":true,"license":"MIT","optional":true,"os":["darwin"],"engines":{"node":">=18"}},
    "node_modules/@esbuild/freebsd-arm64": {"version":"0.28.2","resolved":"https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz","integrity":"sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==","cpu":["arm64"],"dev":true,"license":"MIT","optional":true,"os":["freebsd"],"engines":{"node":">=18"}},
    "node_modules/@esbuild/freebsd-x64": {"version":"0.28.2","resolved":"https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz","integrity":"sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==","cpu":["x64"],"dev":true,"license":"MIT","optional":true,"os":["freebsd"],"engines":{"node":">=18"}},
    "node_modules/@esbuild/linux-arm": {"version":"0.28.2","resolved":"https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz","integrity":"sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==","cpu":["arm"],"dev":true,"license":"MIT","optional":true,"os":["linux"],"engines":{"node":">=18"}},
    "node_modules/@esbuild/linux-arm64": {"version":"0.28.2","resolved":"https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz","integrity":"sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==","cpu":["arm64"],"dev":true,"license":"MIT","optional":true,"os":["linux"],"engines":{"node":">=18"}},
    "node_modules/@esbuild/linux-ia32": {"version":"0.28.2","resolved":"https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz","integrity":"sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==","cpu":["ia32"],"dev":true,"license":"MIT","optional":true,"os":["linux"],"engines":{"node":">=18"}},
    "node_modules/@esbuild/linux-loong64": {"version":"0.28.2","resolved":"https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz","integrity":"sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==","cpu":["loong64"],"dev":true,"license":"MIT","optional":true,"os":["linux"],"engines":{"node":">=18"}},
    "node_modules/@esbuild/linux-mips64el": {"version":"0.28.2","resolved":"https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz","integrity":"sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==","cpu":["mips64el"],"dev":true,"license":"MIT","optional":true,"os":["linux"],"engines":{"node":">=18"}},
    "node_modules/@esbuild/linux-ppc64": {"version":"0.28.2","resolved":"https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz","integrity":"sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==","cpu":["ppc64"],"dev":true,"license":"MIT","optional":true,"os":["linux"],"engines":{"node":">=18"}},
    "node_modules/@esbuild/linux-riscv64": {"version":"0.28.2","resolved":"https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz","integrity":"sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==","cpu":["riscv64"],"dev":true,"license":"MIT","optional":true,"os":["linux"],"engines":{"node":">=18"}},
    "node_modules/@esbuild/linux-s390x": {"version":"0.28.2","resolved":"https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz","integrity":"sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==","cpu":["s390x"],"dev":true,"license":"MIT","optional":true,"os":["linux"],"engines":{"node":">=18"}},
    "node_modules/@esbuild/linux-x64": {"version":"0.28.2","resolved":"https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz","integrity":"sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==","cpu":["x64"],"dev":true,"license":"MIT","optional":true,"os":["linux"],"engines":{"node":">=18"}},
    "node_modules/@esbuild/netbsd-arm64": {"version":"0.28.2","resolved":"https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.2.tgz","integrity":"sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==","cpu":["arm64"],"dev":true,"license":"MIT","optional":true,"os":["netbsd"],"engines":{"node":">=18"}},
    "node_modules/@esbuild/netbsd-x64": {"version":"0.28.2","resolved":"https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz","integrity":"sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==","cpu":["x64"],"dev":true,"license":"MIT","optional":true,"os":["netbsd"],"engines":{"node":">=18"}},
    "node_modules/@esbuild/openbsd-arm64": {"version":"0.28.2","resolved":"https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.2.tgz","integrity":"sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==","cpu":["arm64"],"dev":true,"license":"MIT","optional":true,"os":["openbsd"],"engines":{"node":">=18"}},
    "node_modules/@esbuild/openbsd-x64": {"version":"0.28.2","resolved":"https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz","integrity":"sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==","cpu":["x64"],"dev":true,"license":"MIT","optional":true,"os":["openbsd"],"engines":{"node":">=18"}},
    "node_modules/@esbuild/openharmony-arm64": {"version":"0.28.2","resolved":"https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.2.tgz","integrity":"sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==","cpu":["arm64"],"dev":true,"license":"MIT","optional":true,"os":["openharmony"],"engines":{"node":">=18"}},
    "node_modules/@esbuild/sunos-x64": {"version":"0.28.2","resolved":"https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz","integrity":"sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==","cpu":["x64"],"dev":true,"license":"MIT","optional":true,"os":["sunos"],"engines":{"node":">=18"}},
    "node_modules/@esbuild/win32-arm64": {"version":"0.28.2","resolved":"https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz","integrity":"sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==","cpu":["arm64"],"dev":true,"license":"MIT","optional":true,"os":["win32"],"engines":{"node":">=18"}},
    "node_modules/@esbuild/win32-ia32": {"version":"0.28.2","resolved":"https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz","integrity":"sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==","cpu":["ia32"],"dev":true,"license":"MIT","optional":true,"os":["win32"],"engines":{"node":">=18"}},
    "node_modules/@esbuild/win32-x64": {"version":"0.28.2","resolved":"https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz","integrity":"sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==","cpu":["x64"],"dev":true,"license":"MIT","optional":true,"os":["win32"],"engines":{"node":">=18"}},
    "node_modules/@napi-rs/lzma-linux-x64-gnu": {"version":"1.5.1","resolved":"https://registry.npmjs.org/@napi-rs/lzma-linux-x64-gnu/-/lzma-linux-x64-gnu-1.5.1.tgz","integrity":"sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==","cpu":["x64"],"dev":true,"libc":["glibc"],"license":"MIT","optional":true,"os":["linux"],"engines":{"node":"^22.20 || ^24.12 || >=25"}},
    "node_modules/@rollup/rollup-android-arm-eabi": {"version":"4.63.3","resolved":"https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.63.3.tgz","integrity":"sha512-w3Jnvi1ocaVm/c7yVPpfB98XeSRBMyzp6njL5MVVbGyXjpmUkN+s6Hp4t0PqhGCCaI1ZHMKXt/w0lA1RCaLVcw==","cpu":["arm"],"dev":true,"license":"MIT","optional":true,"os":["android"]},
    "node_modules/@rollup/rollup-android-arm64": {"version":"4.63.3","resolved":"https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.63.3.tgz","integrity":"sha512-uI/ESiaIbbRYAEhzy8PCUWDp1hB0bjAqM06mW9flOoNO4Q8DQpeoREhBR5Hegfl+wpXiguyJv6XSPzEN7OxyHQ==","cpu":["arm64"],"dev":true,"license":"MIT","optional":true,"os":["android"]},
    "node_modules/@rollup/rollup-darwin-arm64": {"version":"4.63.3","resolved":"https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.63.3.tgz","integrity":"sha512-oxhrd1jmXLwWZ83eQYDXxuqRdkqkzrjR3JobKeuUyfdNZo11FuQIvqEOZhyIT7OBHxXoGslDDjN0cQcM6T0TqQ==","cpu":["arm64"],"dev":true,"license":"MIT","optional":true,"os":["darwin"]},
    "node_modules/@rollup/rollup-darwin-x64": {"version":"4.63.3","resolved":"https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.63.3.tgz","integrity":"sha512-7/YiIMghVE8DrxKvNdorAaJVdriOFgOIpdStnPx8ppx5zfTwC3jBCSEAIzB7JD5404m65THl6H93UTTVUvypmg==","cpu":["x64"],"dev":true,"license":"MIT","optional":true,"os":["darwin"]},
    "node_modules/@rollup/rollup-freebsd-arm64": {"version":"4.63.3","resolved":"https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.63.3.tgz","integrity":"sha512-GXFZRRoMAytaI5z6N3Zhfw0WL18Q0M8r95D5hlC4GqE/lGk8pbSJNUBoOWDfbm6dTciqHj2nU87tI5f6XhQiOg==","cpu":["arm64"],"dev":true,"license":"MIT","optional":true,"os":["freebsd"]},
    "node_modules/@rollup/rollup-freebsd-x64": {"version":"4.63.3","resolved":"https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.63.3.tgz","integrity":"sha512-77W+8X3ddYgPxUpB8nZFQs2Mq+wc4HVlcSRtApXLjYBcnPMkttrSnU8VwKQjeWYhMsITHFs5cWBQ8vz1Q+5RHQ==","cpu":["x64"],"dev":true,"license":"MIT","optional":true,"os":["freebsd"]},
    "node_modules/@rollup/rollup-linux-arm-gnueabihf": {"version":"4.63.3","resolved":"https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.63.3.tgz","integrity":"sha512-FVkwK+iUC+mq+GipVK46rRVticfAPtvPUNlqlGXUDxdVk/UGjQiiiUVPUrEXdSpU2ufU0XxLGyTqDtBidDOVmg==","cpu":["arm"],"dev":true,"libc":["glibc"],"license":"MIT","optional":true,"os":["linux"]},
    "node_modules/@rollup/rollup-linux-arm-musleabihf": {"version":"4.63.3","resolved":"https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.63.3.tgz","integrity":"sha512-+aGU1t3398yQOVj1Bz8o3e+KtswxAPvO+mtxtNdfXYMkXIHu7XhhkCD7/DEH9q8tF8uhDnMWvfpUKI8y1sZJsg==","cpu":["arm"],"dev":true,"libc":["musl"],"license":"MIT","optional":true,"os":["linux"]},
    "node_modules/@rollup/rollup-linux-arm64-gnu": {"version":"4.63.3","resolved":"https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.63.3.tgz","integrity":"sha512-cR0kjpRXR2KJ2oQK8E2KTPtphs+b9hZ8IhTZubNryt/RsqgdOZBQ2Zq0q5UedtiIi0rs3jVhJh55RE1ZHUVGUA==","cpu":["arm64"],"dev":true,"libc":["glibc"],"license":"MIT","optional":true,"os":["linux"]},
    "node_modules/@rollup/rollup-linux-arm64-musl": {"version":"4.63.3","resolved":"https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.63.3.tgz","integrity":"sha512-y1RYi4Q3/9ByVWSSt9kX2ustE0B7kFYbJ6zZdVZVyqopZs3yhCTwRfrjIX4vezUJInma/Gs6BOFDJg7yZmJ0IQ==","cpu":["arm64"],"dev":true,"libc":["musl"],"license":"MIT","optional":true,"os":["linux"]},
    "node_modules/@rollup/rollup-linux-loong64-gnu": {"version":"4.63.3","resolved":"https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.63.3.tgz","integrity":"sha512-DNhEA5viIj3Z5bZLE4z4oV8N5ozWqDwyt7T6KG7VdLDJ0nW+rNOYlphBl4/3HQkK75qipPLsVOfStHHOwN9WSg==","cpu":["loong64"],"dev":true,"libc":["glibc"],"license":"MIT","optional":true,"os":["linux"]},
    "node_modules/@rollup/rollup-linux-loong64-musl": {"version":"4.63.3","resolved":"https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.63.3.tgz","integrity":"sha512-17gQCqrIpXBX2Cmi9/TygnVOqGbzsba/iaqcYSL8FY7lNugg+7AiYNs5c5nKWD+NRQha36Sa0CqkJqH4XVHwnQ==","cpu":["loong64"],"dev":true,"libc":["musl"],"license":"MIT","optional":true,"os":["linux"]},
    "node_modules/@rollup/rollup-linux-ppc64-gnu": {"version":"4.63.3","resolved":"https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.63.3.tgz","integrity":"sha512-6LwVnZRIyINpdku/yOcI8Tm9YqLmhHK5emmlOOnW9tO0SYEm1FmKPcsSAGp0NBlqR2P04xaND4jvN6sTHqhq8A==","cpu":["ppc64"],"dev":true,"libc":["glibc"],"license":"MIT","optional":true,"os":["linux"]},
    "node_modules/@rollup/rollup-linux-ppc64-musl": {"version":"4.63.3","resolved":"https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.63.3.tgz","integrity":"sha512-xMUqkTXlEUtI/p5AAukMwBRr1enU3efsTeF+bskeFfk8t1C9rcC8sLREcZXmTfAXEbvRdJVSonVJez3TMlbR3w==","cpu":["ppc64"],"dev":true,"libc":["musl"],"license":"MIT","optional":true,"os":["linux"]},
    "node_modules/@rollup/rollup-linux-riscv64-gnu": {"version":"4.63.3","resolved":"https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.63.3.tgz","integrity":"sha512-S3E94co9F9WRRqEaUoQZ38K1gCz6KiM+nL7/3ijq7fDGF3OznjS5TasgYITlvl27GQKtu4lOAOsr5MFwkijvOA==","cpu":["riscv64"],"dev":true,"libc":["glibc"],"license":"MIT","optional":true,"os":["linux"]},
    "node_modules/@rollup/rollup-linux-riscv64-musl": {"version":"4.63.3","resolved":"https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.63.3.tgz","integrity":"sha512-1QtRDwG42x5BJI3s9mxu5rEjDnfbSnk20HQ9/ylTAYnSwYwxMVb+Vgu34wzzTQ7ogqBybebgQNUDAvZVQ38DbA==","cpu":["riscv64"],"dev":true,"libc":["musl"],"license":"MIT","optional":true,"os":["linux"]},
    "node_modules/@rollup/rollup-linux-s390x-gnu": {"version":"4.63.3","resolved":"https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.63.3.tgz","integrity":"sha512-BQhejF6ZXOpxbngiNTP12GCGQeaDVL2QXGeBVViKIYzFHM5RKxTxwUMB1fr1BeNFphFMpnRqC5QSXFSa4z6UQw==","cpu":["s390x"],"dev":true,"libc":["glibc"],"license":"MIT","optional":true,"os":["linux"]},
    "node_modules/@rollup/rollup-linux-x64-gnu": {"version":"4.63.3","resolved":"https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.63.3.tgz","integrity":"sha512-SXagRwnI2Wlwlitllu59UK/nGVbD1CKPcNqDplHwIC4BqJcpXFjD32d1R/RbuISa95HdQrZM3/7v4bKiowFaLA==","cpu":["x64"],"dev":true,"libc":["glibc"],"license":"MIT","optional":true,"os":["linux"]},
    "node_modules/@rollup/rollup-linux-x64-musl": {"version":"4.63.3","resolved":"https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.63.3.tgz","integrity":"sha512-2IPozoEALRCziGqE8O9KMK60PMu5TS1huv4fwoeCexj+WjmcwFtX9CTOVbfXCUqcELAubEwRFPYlzb/WvwY2HQ==","cpu":["x64"],"dev":true,"libc":["musl"],"license":"MIT","optional":true,"os":["linux"]},
    "node_modules/@rollup/rollup-openbsd-x64": {"version":"4.63.3","resolved":"https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.63.3.tgz","integrity":"sha512-AoxqosUHT9IX54hFn2TiN6A7d6ZKTtE6pd2bqWtqkkNJ6HJGaU6FRouGX8L1O7R/ZwsnCnpQrHzb4pDEx+UHRQ==","cpu":["x64"],"dev":true,"license":"MIT","optional":true,"os":["openbsd"]},
    "node_modules/@rollup/rollup-openharmony-arm64": {"version":"4.63.3","resolved":"https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.63.3.tgz","integrity":"sha512-d+CaftKgmkFBzCwezMqqy1d0QNNYugqLCMcYVQWBy5SS2YfeMP8Q8ripkgx9O8IyBXXLHrJ+aaCV4U96usv6Yg==","cpu":["arm64"],"dev":true,"license":"MIT","optional":true,"os":["openharmony"]},
    "node_modules/@rollup/rollup-win32-arm64-msvc": {"version":"4.63.3","resolved":"https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.63.3.tgz","integrity":"sha512-xXlDF6nR1eOuXbdDy5Hl5fmtY7teUDevF/k0O7IPoZe4Tpmdv+lgdE5JRsnhQtt37ql9P0VF2kAN9a0OCZdo+Q==","cpu":["arm64"],"dev":true,"license":"MIT","optional":true,"os":["win32"]},
    "node_modules/@rollup/rollup-win32-ia32-msvc": {"version":"4.63.3","resolved":"https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.63.3.tgz","integrity":"sha512-YtXAgLN+JP7Ay6qG3eWhc7IHMQPzLc8r3uvhAvlJIoCz/4Q32+Bl9Fmnywidh8v1GOIMmymjovfqY9ETAtysvA==","cpu":["ia32"],"dev":true,"license":"MIT","optional":true,"os":["win32"]},
    "node_modules/@rollup/rollup-win32-x64-gnu": {"version":"4.63.3","resolved":"https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.63.3.tgz","integrity":"sha512-WuWtSJRNo549vzcfZyEgfqb6zeSgn1F+UE5kQ+BCjzz0W4MGCjntUHkZVc1VRuAM7+ULaSyhiPxD1spyewFvkQ==","cpu":["x64"],"dev":true,"license":"MIT","optional":true,"os":["win32"]},
    "node_modules/@rollup/rollup-win32-x64-msvc": {"version":"4.63.3","resolved":"https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.63.3.tgz","integrity":"sha512-+lIKX7O0+IGe7WuhATaAMMeT7B76vfhXH/l9wLQL+nvyhbw2ohYCKIdWL56JfDu75CWt5oKRP4QFH/jkMtBquA==","cpu":["x64"],"dev":true,"license":"MIT","optional":true,"os":["win32"]},
    "node_modules/@types/estree": {"version":"1.0.9","resolved":"https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz","integrity":"sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==","dev":true,"license":"MIT"},
    "node_modules/@types/prop-types": {"version":"15.7.15","resolved":"https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz","integrity":"sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==","dev":true,"license":"MIT"},
    "node_modules/@types/react": {"version":"18.3.23","resolved":"https://registry.npmjs.org/@types/react/-/react-18.3.23.tgz","integrity":"sha512-/LDXMQh55EzZQ0uVAZmKKhfENivEvWz6E+EYzh+/MCjMhNsotd+ZHhBGIjFDTi6+fz0OhQQQLbTgdQIxxCsC0w==","dev":true,"license":"MIT","dependencies":{"@types/prop-types":"*","csstype":"^3.0.2"}},
    "node_modules/@types/react-dom": {"version":"18.3.7","resolved":"https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz","integrity":"sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==","dev":true,"license":"MIT","peerDependencies":{"@types/react":"^18.0.0"}},
    "node_modules/csstype": {"version":"3.2.3","resolved":"https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz","integrity":"sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==","dev":true,"license":"MIT"},
    "node_modules/esbuild": {"version":"0.28.2","resolved":"https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz","integrity":"sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==","dev":true,"hasInstallScript":true,"license":"MIT","bin":{"esbuild":"bin/esbuild"},"engines":{"node":">=18"},"optionalDependencies":{"@esbuild/aix-ppc64":"0.28.2","@esbuild/android-arm":"0.28.2","@esbuild/android-arm64":"0.28.2","@esbuild/android-x64":"0.28.2","@esbuild/darwin-arm64":"0.28.2","@esbuild/darwin-x64":"0.28.2","@esbuild/freebsd-arm64":"0.28.2","@esbuild/freebsd-x64":"0.28.2","@esbuild/linux-arm":"0.28.2","@esbuild/linux-arm64":"0.28.2","@esbuild/linux-ia32":"0.28.2","@esbuild/linux-loong64":"0.28.2","@esbuild/linux-mips64el":"0.28.2","@esbuild/linux-ppc64":"0.28.2","@esbuild/linux-riscv64":"0.28.2","@esbuild/linux-s390x":"0.28.2","@esbuild/linux-x64":"0.28.2","@esbuild/netbsd-arm64":"0.28.2","@esbuild/netbsd-x64":"0.28.2","@esbuild/openbsd-arm64":"0.28.2","@esbuild/openbsd-x64":"0.28.2","@esbuild/openharmony-arm64":"0.28.2","@esbuild/sunos-x64":"0.28.2","@esbuild/win32-arm64":"0.28.2","@esbuild/win32-ia32":"0.28.2","@esbuild/win32-x64":"0.28.2"}},
    "node_modules/fdir": {"version":"6.5.0","resolved":"https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz","integrity":"sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==","dev":true,"license":"MIT","engines":{"node":">=12.0.0"},"peerDependencies":{"picomatch":"^3 || ^4"},"peerDependenciesMeta":{"picomatch":{"optional":true}}},
    "node_modules/fsevents": {"version":"2.3.3","resolved":"https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz","integrity":"sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==","dev":true,"hasInstallScript":true,"license":"MIT","optional":true,"os":["darwin"],"engines":{"node":"^8.16.0 || ^10.6.0 || >=11.0.0"}},
    "node_modules/js-tokens": {"version":"4.0.0","resolved":"https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz","integrity":"sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==","license":"MIT"},
    "node_modules/loose-envify": {"version":"1.4.0","resolved":"https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz","integrity":"sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==","license":"MIT","dependencies":{"js-tokens":"^3.0.0 || ^4.0.0"},"bin":{"loose-envify":"cli.js"}},
    "node_modules/nanoid": {"version":"3.3.19","resolved":"https://registry.npmjs.org/nanoid/-/nanoid-3.3.19.tgz","integrity":"sha512-Y2tUNy4ouw6tq5oDSKeQYGOyhkUBhNOcGV/02KC+6kd9eDGqdZd++mjMiIDilrBYvjEnCYvVtsuHCuP+okSfug==","dev":true,"funding":[{"type":"github","url":"https://github.com/sponsors/ai"}],"license":"MIT","bin":{"nanoid":"bin/nanoid.cjs"},"engines":{"node":"^10 || ^12 || ^13.7 || ^14 || >=15.0.1"}},
    "node_modules/picocolors": {"version":"1.1.1","resolved":"https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz","integrity":"sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==","dev":true,"license":"ISC"},
    "node_modules/picomatch": {"version":"4.0.7","resolved":"https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz","integrity":"sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==","dev":true,"license":"MIT","engines":{"node":">=12"},"funding":{"url":"https://github.com/sponsors/jonschlinkert"}},
    "node_modules/postcss": {"version":"8.5.28","resolved":"https://registry.npmjs.org/postcss/-/postcss-8.5.28.tgz","integrity":"sha512-RRuzqDtt5Y9h3quz5hWhK+TPnsmVs6WwSU6LkJMeY4HstUEDuYTG8UJSdawMRzmzAtV+KEoG8N3Qg2qLy5vM/A==","dev":true,"funding":[{"type":"opencollective","url":"https://opencollective.com/postcss/"},{"type":"tidelift","url":"https://tidelift.com/funding/github/npm/postcss"},{"type":"github","url":"https://github.com/sponsors/ai"}],"license":"MIT","dependencies":{"nanoid":"^3.3.18","picocolors":"^1.1.1","source-map-js":"^1.2.1"},"engines":{"node":"^10 || ^12 || >=14"}},
    "node_modules/react": {"version":"18.3.1","resolved":"https://registry.npmjs.org/react/-/react-18.3.1.tgz","integrity":"sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==","license":"MIT","dependencies":{"loose-envify":"^1.1.0"},"engines":{"node":">=0.10.0"}},
    "node_modules/react-dom": {"version":"18.3.1","resolved":"https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz","integrity":"sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==","license":"MIT","dependencies":{"loose-envify":"^1.1.0","scheduler":"^0.23.2"},"peerDependencies":{"react":"^18.3.1"}},
    "node_modules/rollup": {"version":"4.63.3","resolved":"https://registry.npmjs.org/rollup/-/rollup-4.63.3.tgz","integrity":"sha512-1i2XreiAoMMXuPGD6Msj2xWrMMkHojNRKivInxGQcg7/1KuPuYlfUutLyh4drnOxUTHX9cHI4wFoat8D/NKaBw==","dev":true,"license":"MIT","dependencies":{"@types/estree":"1.0.9"},"bin":{"rollup":"dist/bin/rollup"},"engines":{"node":">=18.0.0","npm":">=8.0.0"},"optionalDependencies":{"@napi-rs/lzma-linux-x64-gnu":"1.5.1","@rollup/rollup-android-arm-eabi":"4.63.3","@rollup/rollup-android-arm64":"4.63.3","@rollup/rollup-darwin-arm64":"4.63.3","@rollup/rollup-darwin-x64":"4.63.3","@rollup/rollup-freebsd-arm64":"4.63.3","@rollup/rollup-freebsd-x64":"4.63.3","@rollup/rollup-linux-arm-gnueabihf":"4.63.3","@rollup/rollup-linux-arm-musleabihf":"4.63.3","@rollup/rollup-linux-arm64-gnu":"4.63.3","@rollup/rollup-linux-arm64-musl":"4.63.3","@rollup/rollup-linux-loong64-gnu":"4.63.3","@rollup/rollup-linux-loong64-musl":"4.63.3","@rollup/rollup-linux-ppc64-gnu":"4.63.3","@rollup/rollup-linux-ppc64-musl":"4.63.3","@rollup/rollup-linux-riscv64-gnu":"4.63.3","@rollup/rollup-linux-riscv64-musl":"4.63.3","@rollup/rollup-linux-s390x-gnu":"4.63.3","@rollup/rollup-linux-x64-gnu":"4.63.3","@rollup/rollup-linux-x64-musl":"4.63.3","@rollup/rollup-openbsd-x64":"4.63.3","@rollup/rollup-openharmony-arm64":"4.63.3","@rollup/rollup-win32-arm64-msvc":"4.63.3","@rollup/rollup-win32-ia32-msvc":"4.63.3","@rollup/rollup-win32-x64-gnu":"4.63.3","@rollup/rollup-win32-x64-msvc":"4.63.3","fsevents":"~2.3.2"}},
    "node_modules/scheduler": {"version":"0.23.2","resolved":"https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz","integrity":"sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==","license":"MIT","dependencies":{"loose-envify":"^1.1.0"}},
    "node_modules/source-map-js": {"version":"1.2.1","resolved":"https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz","integrity":"sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==","dev":true,"license":"BSD-3-Clause","engines":{"node":">=0.10.0"}},
    "node_modules/tinyglobby": {"version":"0.2.17","resolved":"https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz","integrity":"sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==","dev":true,"license":"MIT","dependencies":{"fdir":"^6.5.0","picomatch":"^4.0.4"},"engines":{"node":">=12.0.0"},"funding":{"url":"https://github.com/sponsors/SuperchupuDev"}},
    "node_modules/typescript": {"version":"5.9.2","resolved":"https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz","integrity":"sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==","dev":true,"license":"Apache-2.0","bin":{"tsc":"bin/tsc","tsserver":"bin/tsserver"},"engines":{"node":">=14.17"}},
    "node_modules/vite": {"version":"7.3.6","resolved":"https://registry.npmjs.org/vite/-/vite-7.3.6.tgz","integrity":"sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg==","dev":true,"license":"MIT","dependencies":{"esbuild":"^0.27.0 || ^0.28.0","fdir":"^6.5.0","picomatch":"^4.0.3","postcss":"^8.5.6","rollup":"^4.43.0","tinyglobby":"^0.2.15"},"bin":{"vite":"bin/vite.js"},"engines":{"node":"^20.19.0 || >=22.12.0"},"funding":{"url":"https://github.com/vitejs/vite?sponsor=1"},"optionalDependencies":{"fsevents":"~2.3.3"},"peerDependencies":{"@types/node":"^20.19.0 || >=22.12.0","jiti":">=1.21.0","less":"^4.0.0","lightningcss":"^1.21.0","sass":"^1.70.0","sass-embedded":"^1.70.0","stylus":">=0.54.8","sugarss":"^5.0.0","terser":"^5.16.0","tsx":"^4.8.1","yaml":"^2.4.2"},"peerDependenciesMeta":{"@types/node":{"optional":true},"jiti":{"optional":true},"less":{"optional":true},"lightningcss":{"optional":true},"sass":{"optional":true},"sass-embedded":{"optional":true},"stylus":{"optional":true},"sugarss":{"optional":true},"terser":{"optional":true},"tsx":{"optional":true},"yaml":{"optional":true}}}
  }
}

Check the attempt

Use both instances, then reload with ?fixture=changed, ?fixture=transfer, ?fixture=empty and ?fixture=hundred. These are fixture names for this local host, not additional component props.

  • Compare the callback log with the displayed commitment. Check original-object identity and exact callback counts for commits, recommits and edits.
  • Try both arrow bounds, exact-label typing, case-equivalent labels, significant spaces, no results and all 100 options. Replace one two-match query with a different two-match query.
  • Check Escape, click/arrow reopening, real Tab and Shift+Tab traversal, caret keys and modified editing shortcuts.
  • Exercise composition start/end boundaries separately from normal Enter. Record which events you simulated and which IME you actually used.
  • Try mouse activation, a drag that ends without activation, pointer cancellation and touch scrolling. A scroll must not become a choice.
  • Inspect listbox relationships, active descendants and distinct IDs across two instances. At 320, 375, 768 and 1024 pixels, check long labels and the last active option. Try forced colors and reduced motion.

Stopping point: demonstrate the behavior on changed data and explain why draft text, active option and commitment are separate. A self-reported checkmark or finite set of passing checks is not proof of mastery.

An optional follow-up is to describe what remote results would change. Don't build that backend for this task.

Take a moment to think about this before revealing the answer

Explain your reasoning or try an implementation before comparing answers.

Explore the full Frontend Interviews material

Premium includes the complete lessons and implementation references. Free practice questions remain available without a subscription.

All course tracks & premium content
From basics to advanced masterclasses
Built for JS/TS developers like you
Real-world tips & common pitfalls
Upgrade to Premium