Inputs

Search field and suggestions

Use SearchBar for controlled query strings with the same input styling as the rest of the kit. Pair it with SearchSuggestionList when you want a lightweight list of matches—without wiring a full modal or command palette.

Controlled example

Inline search and list

Filter the sample entries below. Use arrow keys and Enter from the field; selection updates local state only (no navigation on this demo page).

Type to filter the sample routes.

Disabled state

Same styles with interaction turned off.

CSS variable overrides

SearchBar composes the Input recipe, so these are the zui variables available through the search input.

107 variables

Pattern: --zui-<component>-<slot?>-<variant?>-<property>-<state?>-dark?

:root {
  --zui-input-bg: #0000000d;
  --zui-input-fg: oklch(20.8% 0.042 265.755);
  --zui-input-shadow: 0 1px 2px rgba(15,23,42,0.08);
  --zui-input-ring-offset: oklch(98.4% 0.003 247.858);
  --zui-input-placeholder-fg: oklch(55.4% 0.046 257.417);
  --zui-input-bg-read-only: #00000008;
  --zui-input-file-border: #0000001a;
  --zui-input-file-bg: #0000001a;
  --zui-input-file-fg: oklch(37.2% 0.044 257.287);
  --zui-input-file-bg-hover: #00000026;
  --zui-input-file-fg-hover: #ffffff;
  --zui-input-checkbox-border: #0000004d;
  --zui-input-checkbox-bg: transparent;
  --zui-input-radio-border: #0000004d;
  --zui-input-radio-bg: transparent;
  --zui-input-radio-bg-read-only: transparent;
  --zui-input-radio-ring: #00000033;
  --zui-input-radio-ring-offset: oklch(98.4% 0.003 247.858);
  --zui-input-default-border: #0000001a;
  --zui-input-default-border-focus: #00000033;
  --zui-input-warning-border: oklch(79.5% 0.184 86.047 / 0.8);
  --zui-input-warning-fg: oklch(28.6% 0.066 53.813);
  --zui-input-warning-placeholder-fg: oklch(47.6% 0.114 61.907);
  --zui-input-warning-border-focus: oklch(68.1% 0.162 75.834);
  --zui-input-warning-ring-focus: oklch(85.2% 0.199 91.936 / 0.8);
  --zui-input-error-border: oklch(64.5% 0.246 16.439 / 0.8);
  --zui-input-error-fg: oklch(27.1% 0.105 12.094);
  --zui-input-error-placeholder-fg: oklch(45.5% 0.188 13.697);
  --zui-input-error-border-focus: oklch(58.6% 0.253 17.585);
  --zui-input-error-ring-focus: oklch(71.2% 0.194 13.428 / 0.8);
  --zui-input-success-border: oklch(69.6% 0.17 162.48 / 0.7);
  --zui-input-success-fg: oklch(26.2% 0.051 172.552);
  --zui-input-success-placeholder-fg: oklch(43.2% 0.095 166.913);
  --zui-input-success-border-focus: oklch(59.6% 0.145 163.225);
  --zui-input-success-ring-focus: oklch(76.5% 0.177 163.223 / 0.8);
  --zui-input-info-border: oklch(62.3% 0.214 259.815 / 0.8);
  --zui-input-info-fg: oklch(28.2% 0.091 267.935);
  --zui-input-info-placeholder-fg: oklch(42.4% 0.199 265.638);
  --zui-input-info-border-focus: oklch(54.6% 0.245 262.881);
  --zui-input-info-ring-focus: oklch(70.7% 0.165 254.624 / 0.8);
  --zui-input-violet-border: oklch(60.6% 0.25 292.717 / 0.8);
  --zui-input-violet-fg: oklch(28.3% 0.141 291.089);
  --zui-input-violet-placeholder-fg: oklch(43.2% 0.232 292.759);
  --zui-input-violet-border-focus: oklch(54.1% 0.281 293.009);
  --zui-input-violet-ring-focus: oklch(70.2% 0.183 293.541 / 0.8);
  --zui-input-amber-border: oklch(76.9% 0.188 70.08 / 0.8);
  --zui-input-amber-fg: oklch(27.9% 0.077 45.635);
  --zui-input-amber-placeholder-fg: oklch(47.3% 0.137 46.201);
  --zui-input-amber-border-focus: oklch(66.6% 0.179 58.318);
  --zui-input-amber-ring-focus: oklch(82.8% 0.189 84.429 / 0.8);
  --zui-input-pink-border: oklch(65.6% 0.241 354.308 / 0.8);
  --zui-input-pink-fg: oklch(28.4% 0.109 3.907);
  --zui-input-pink-placeholder-fg: oklch(45.9% 0.187 3.815);
  --zui-input-pink-border-focus: oklch(59.2% 0.249 0.584);
  --zui-input-pink-ring-focus: oklch(71.8% 0.202 349.761 / 0.8);
  --zui-input-indigo-border: oklch(58.5% 0.233 277.117 / 0.8);
  --zui-input-indigo-fg: oklch(25.7% 0.09 281.288);
  --zui-input-indigo-placeholder-fg: oklch(39.8% 0.195 277.366);
  --zui-input-indigo-border-focus: oklch(51.1% 0.262 276.966);
  --zui-input-indigo-ring-focus: oklch(67.3% 0.182 276.935 / 0.8);
  --zui-input-orange-border: oklch(70.5% 0.213 47.604 / 0.8);
  --zui-input-orange-fg: oklch(26.6% 0.079 36.259);
  --zui-input-orange-placeholder-fg: oklch(47% 0.157 37.304);
  --zui-input-orange-border-focus: oklch(64.6% 0.222 41.116);
  --zui-input-orange-ring-focus: oklch(75% 0.183 55.934 / 0.8);
}

/* Dark theme variables follow the same names with -dark appended. */
.dark {
  --zui-input-bg-dark: #ffffff0d;
  --zui-input-fg-dark: oklch(98.4% 0.003 247.858);
  /* ...same variables with -dark at the end */
}

What it does

SearchBar wraps a native input with optional leadingSlot (for example a search icon). SearchSuggestionList renders grouped rows as buttons for pointer and keyboard focus.

Neither component fetches data or owns navigation—you control value, filtering, and routing.

Composition and API

Keep filtering logic in the parent or a small hook. Cap result counts for performance on large indexes.

Use consistent ids for list items so selection handlers stay stable.

Common use cases

  • Documentation or marketing site search over static routes.
  • Filter narrow lists in settings or admin tables.
  • Prototype command palettes before adding keyboard shortcuts.
  • Search-as-you-type with your own ranking or API.

Accessibility

Provide a visible label or aria-label on SearchBar. For inline suggestion lists, ensure focus order matches user expectations when combining with dialogs.

This preview exposes a single h1 in the hero.

Next.js integration notes

Import from @zentauri-ui/zentauri-components/ui/search. Rebuild the components package after API changes so types and bundles stay in sync.

Set NEXT_PUBLIC_SITE_URL so canonical and Open Graph URLs resolve on deploy.

FAQ

Does SearchBar work with the Next.js App Router?

Yes. Use it inside a client component when you need useState for the value; keep surrounding layout in server components if you prefer.

Is a modal required?

No. SearchBar and SearchSuggestionList are presentational. You can render them inline on a page or wrap them in your own dialog when you need one.

How do I connect SearchSuggestionList to data?

Filter your items in the parent, map them to { id, label, description?, group? }, and pass them to SearchSuggestionList with an onSelect handler.