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.
Theory questions
Frontend Behavioral Questions: The Three Story Types
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.
Live-Coding a React Component: What Interviewers Watch For
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.
The Five Frontend Interview Formats
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.
JavaScript Implementation Challenges Catalog
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.
Frontend System Design: The 6-Step Framework
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.
Coding practice
Build a Local Autocomplete
Implement and check your solution in the stated environment before revealing the answer.
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:
| Prop | Contract |
|---|---|
label | A nonempty visible label for the text input |
options | An immutable array of 0 to 100 original option objects. Each object has a unique nonempty opaque string id and a label |
onSelectionChange | Receive 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 state | What should happen |
|---|---|
| Initial mount | Empty text, no highlight or commitment and no visible results/status. No autofocus or callback |
| Focus or click the input | Open matches without choosing a highlight. Show status instead if there are no matches |
| Actual text change | Keep 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 highlight | Open results and highlight the first match. With no matches, keep the highlight absent |
| Up with no highlight | Open results and highlight the last match |
| Further plain Up or Down | Move one visible option and clamp at each end. Don't wrap or move the text caret |
| Plain Enter with an active visible option | Commit that original object once, copy its label into the input, close results/status and clear the highlight |
| Enter without an active visible option | Do nothing. Typing an exact label is not an implicit commit |
| Explicitly commit the same option again | Notify once again, even if its ID is still the committed ID |
| Pointer activation of an option | Commit once, keep or return input focus and stay closed after focus returns |
| Pointer drag, cancel or touch scroll | Don't commit. Touch scrolling must still work. Don't unmount a genuine click target before its activation |
| Escape, open or closed | Close results/status and clear the highlight. Preserve the text and any valid commitment |
| Reopen after Escape or commit | Input click or Up/Down must work without a blur/refocus round trip |
| Tab or Shift+Tab | Close without committing and allow native traversal. Options must not be extra Tab stops |
| Blur outside the widget | Close without committing. Account for pointer activation before dismissing its target |
| Home, End, Left or Right | Clear the highlight and preserve native caret/selection behavior |
| Modifiers and editing shortcuts | Preserve copy, paste, selection, Backspace/Delete and platform shortcuts. Don't interpret modified arrows, Enter or Escape as plain commands |
| Mere highlight or dismissal | No 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-activedescendantonly to the active visible option. The option'saria-selecteddescribes 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.
| Trace | Expected result |
|---|---|
Focus, type AL | Alpha, Alpine and Alphabet. No highlight or commitment |
| Down, Down, Enter | Commit the original Alpine object once. Input becomes Alpine and results close |
| Click input, Escape | Keep committed Alpine without another callback |
Edit to Alpin, then Alpi | One null callback on the first edit, none on the next |
Type exact Beta, then Enter without an arrow | No commitment |
Type zz | No results, no active descendant and no selectable row |
In the changed fixture, type a, Down, Down, then replace the text with d | Both filters have two matches. The old highlight must still clear and Enter must commit nothing |
| Open a list, Tab, Shift+Tab | Reach 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.