GitHubnpm

Accent theme

Base radius

GitHubnpm

Accent theme

Base radius

Colour scheme

Docs menu

Guides


Primitives
Forms
Layout
Feedback
Overlays
Navigation
Data Display
AI

Combobox

The WAI-ARIA 1.2 combobox pattern: a real <input role="combobox"> that keeps DOM focus the whole time you're typing, with aria-activedescendant pointing at whichever option in the role="listbox" popup is highlighted, the highlight moves, focus doesn't. popover="manual" is used deliberately here: a combobox needs its own open/close rules (open on focus or on typing, not just a single click), so outside-click and Escape dismissal are handled by hand rather than relying on popover="auto".

Astro
Next.js
Remix
SvelteKit
Nuxt
Usage
import { useState } from "react";
import { Combobox } from "@kernelui-lib/react";

const frameworks = [
  { value: "astro", label: "Astro" },
  { value: "next", label: "Next.js" },
  { value: "remix", label: "Remix" },
];

function FrameworkPicker() {
  const [value, setValue] = useState("");

  return (
    <Combobox
      label="Framework"
      options={frameworks}
      value={value}
      onValueChange={setValue}
      placeholder="Search frameworks…"
    />
  );
}

Playground

Toggle every adjustable prop and watch the component — and the code — update live.

Astro
Next.js
Remix
SvelteKit
Nuxt
Unstyled

Same component — Kernel look stripped. See Platforms.

hide label
label offset
placement
align
Usage
<Combobox
  label="Framework"
  options={frameworks}
  placeholder="Search frameworks…"
  emptyMessage="No frameworks found."
/>

Grouping & custom rendering

Pass groups instead of a flat options array to section the listbox under labelled headers — filtering, keyboard navigation, and aria-activedescendant all operate across the flattened result set, so an item's position in its group doesn't change how Arrow Up/Down or Enter behave. renderOption replaces an option's default text label with anything you want (icons, a checkmark, secondary text), given the option, whether it's active or selected, and which group (if any) it belongs to.

Astro
Next.js
Remix
Express
Fastify
Usage
import { Combobox } from "@kernelui-lib/react";
import type { ComboboxGroup, ComboboxOption } from "@kernelui-lib/react";

const groups: ComboboxGroup[] = [
  { id: "frontend", label: "Frontend", items: [
    { value: "astro", label: "Astro" },
    { value: "next", label: "Next.js" },
  ] },
  { id: "backend", label: "Backend", items: [
    { value: "express", label: "Express" },
  ] },
];

function renderOption(option: ComboboxOption, state: { selected: boolean }) {
  return (
    <span>
      {option.label}
      {state.selected ? " ✓" : null}
    </span>
  );
}

<Combobox label="Framework" groups={groups} renderOption={renderOption} />;

Composable options

Use the compound API when each option needs product-owned markup, active-state styling, or grouped asynchronous results. The same input-focused keyboard and listbox behavior stays in Kernel.

Astro
React
Bun
Node.js

Props

Props for Combobox.
PropTypeDefault
labelReactNode (required)
hideLabelbooleanfalse
labelOffsetbooleantrue
options{ value, label }[]
groups{ id, label?, items: ComboboxOption[] }[]
renderOption(option, { active, selected, group?, index }) => ReactNode
value / onValueChangestring / (value) => void
defaultValuestring""
placeholderstring
emptyMessageReactNode"No results"
placement"top" | "bottom" | "left" | "right""bottom"
align"start" | "center" | "end""center"
offsetnumber (px)8

Provide either options or groups — when both are set, groups wins. Each group needs a unique id; a group without a label renders its items without a header.

Accessibility

  • Grouped options are wrapped in role="group", labelled via aria-labelledby by a role="presentation" header, so assistive tech announces which group an option belongs to.