Combobox

Searchable select input for filtering and selecting items from large datasets.

Overview

The Combobox component is a core building block of the Byteion design system, providing a robust, accessibility-compliant interface for its specific UI capabilities.

Why this exists

When a select has many options, a searchable combobox dramatically reduces selection time. It combines the discoverability of a dropdown with the precision of search.

Mental model

A combobox is a searchable select. Type to filter, arrow to navigate, Enter to select. It replaces a select when options exceed ~10.

When to use

• Country, city, or product selection (100+ options) • Tag assignment • User mention (@username) • Any select with too many options to scan

When not to use

• Do not use for fewer than 5 options — a select is faster • Avoid for boolean choices — use a switch • Do not use when options are dynamic and unknown — use free-text input

Basic example

The following example demonstrates standard usage, fully compliant with Byteion's token-first approach.

Variants

Each variant communicates a different meaning. Choose based on priority, not aesthetics.

Single default variant.

Sizes

Size should match the importance and context of the component.

  • md — md size.

States

This component reacts seamlessly to the following interaction and data states:

  • default — Resting appearance before interaction.
  • hover — Pointer is over the element — visual feedback via color or shadow.
  • focus — Keyboard or tab focus — shows ring indicator for accessibility.
  • active — Currently selected or in use.
  • disabled — Non-interactive — grayed out, cursor not-allowed.
  • loading — Action in progress — spinner replaces icon, button is disabled.
  • open — Component is expanded or visible.
  • closed — Component is collapsed or hidden.

Anatomy

• Input field — type to filter • Dropdown panel — filtered options • Option — each selectable item • Empty state — no results message • Chevron — opens dropdown

Usage guidelines

  • Filter on input, debounce by 150ms.
  • Highlight the first match automatically.
  • Show an empty state when no results match.

Do and Don't

Do

  • Debounce filtering.
  • Auto-highlight first match.
  • Show"No results" state.

Don't

  • Do not filter on every keystroke without debounce.
  • Do not close dropdown on no results.
  • Do not use for small option lists.

Accessibility

Role combobox with aria-expanded, aria-activedescendant. Arrow keys navigate, Enter selects, Escape closes.

Role:combobox

ARIA Attributes

  • aria-expanded
  • aria-controls
  • aria-activedescendant

Keyboard Navigation

  • Click/focus: Opens the list without pre-highlighting the first option
  • ArrowDown: Opens the list or moves the active option to the next item
  • ArrowUp: Opens the list or moves the active option to the previous item
  • Enter: Selects the active option when one exists
  • Escape: Closes the overlay or cancels the action

Customization

Dropdown follows popover tokens.

Compose with React cva()

Use the exportedcva() +cn() utilities to compose your own variant on top of the Byteion tokens.

import { cva, cn, type VariantProps } from '@byteion/react';

const myCombobox = cva('base classes…', {
 variants: {
  accent: { soft:'border-primary-200', loud:'border-primary-500' },
 },
 defaultVariants: { accent:'soft' },
});

type Props = React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof myCombobox>;

Compose with Vue cva()

Use the exportedcva() +cn() utilities inside standard Vue setup blocks.

<script setup lang="ts">
import { computed, useAttrs } from 'vue';
import { cva, type VariantProps } from '@byteion/vue';

interface Props { accent?:'soft' |'loud' }
const props = withDefaults(defineProps<Props>(), { accent:'soft' });
const attrs = useAttrs();

const myCombobox = cva('base classes…', {
  variants: { accent: { soft:'border-primary-200', loud:'border-primary-500' } },
});

const cls = computed(() => myCombobox({ accent: props.accent, class: attrs.class as string | undefined }));
</script>

Runtime events

Byteion keeps framework APIs idiomatic: HTML uses DOM custom events, React uses callback props, and Vue uses emitted events / v-model updates.

HTML / JS events

  • bi:combobox:close
  • bi:combobox:error
  • bi:combobox:load
  • bi:combobox:open
  • bi:combobox:search
  • bi:combobox:select

React callbacks

  • onValueChange(value: string | null) => void

Vue emits

  • update:modelValue[value: string]

Remote / AJAX

Remote search

Add data-bi-source to opt into AJAX search. The runtime keeps local filtering as the default, debounces requests, aborts stale requests, updates data-bi-async-state, and renders loading, empty, and error status rows in the listbox.

Attributes

  • data-bi-source
  • data-bi-search-param
  • data-bi-min-chars
  • data-bi-debounce
  • data-bi-value-field
  • data-bi-label-field
  • data-bi-loading-text
  • data-bi-empty-text
  • data-bi-error-text

Runtime events

  • bi:combobox:search
  • bi:combobox:load
  • bi:combobox:error
  • bi:combobox:select
Backend response: Remote endpoints must return JSON. Byteion accepts an array or an object with data, items, results, or options. Each item can be a string/number or an object; value resolves from value, id, or key, and label resolves from label, name, text, or the value. Override object fields with data-bi-value-field and data-bi-label-field.

Accessibility: loading sets aria-busy="true"; empty states use role="status"; error states use alert/status messaging where the runtime renders remote status rows.

API Reference

Requires data-bi-component="combobox" for JS behavior.

HTML Data Attributes

No custom data attributes required.

React Props · ComboboxProps

Extracted directly fromreact/src/components/Combobox.tsx.

export interface ComboboxProps {
  options: ComboboxOption[];
  /** Controlled selected value. */
  value?: string | null;
  defaultValue?: string | null;
  onValueChange?: (value: string | null) => void;
  label?: ReactNode;
  helperText?: ReactNode;
  error?: ReactNode;
  placeholder?: string;
  /** Text shown when no matches are found. */
  emptyMessage?: ReactNode;
  disabled?: boolean;
  /** Allow clearing the selection. */
  clearable?: boolean;
  /** Render the popup open initially. Useful for documentation showcases. */
  defaultOpen?: boolean;
  id?: string;
  className?: string;
}

Vue Props · ComboboxProps

Extracted directly fromvue/src/components/Combobox.vue.

export interface ComboboxProps {
  modelValue?: string;
  defaultValue?: string;
  options: ComboboxOption[];
  placeholder?: string;
  label?: string;
  helperText?: string;
  error?: string;
  disabled?: boolean;
  defaultOpen?: boolean;
  emptyMessage?: string;
  id?: string;
}

Developer tips

• Best practice: support both mouse click and keyboard selection. • Edge case: handle async data — show a loading spinner while fetching options.

Common mistakes

Avoid hardcoded neutral colors, placeholder-only labels, duplicated primary actions, and missing keyboard states. Keep this component on Byteion tokens so dashboard, admin, POS, ERP, ecommerce back-office, Laravel, React, and Vue starter-kit screens can be rebranded without rewriting markup.

Production usage tips

Use the canonical HTML as the source of truth, keep React and Vue wrappers aligned with the documented variants, test dark mode and branded themes before release, and wire interactive behavior through data-bi-* attributes instead of styling hooks.

Premium examples

Advanced patterns available in Byteion Pro:

• Multi-select combobox with tag pills • Virtualized list for 10,000+ options • Grouped options with headers

Unlock Premium Patterns

Get access to copy-paste ready Pro blocks, SaaS templates, and advanced data-tables built with this component.

Explore Pro Components