Ariakit
/

Radix Combobox

Using just the necessary Ariakit components to build a Combobox with Radix UI. For projects already using Radix UI and looking for autocomplete, autosuggest and search features.

Live example

import {
} from "@ariakit/react";
import * as RadixPopover from "@radix-ui/react-popover";
import { useRef, useState } from "react";
import "./style.css";
export default function Example() {
const comboboxRef = useRef<HTMLInputElement>(null);
const listboxRef = useRef<HTMLDivElement>(null);
const [open, setOpen] = useState(false);
return (
<RadixPopover.Root open={open} onOpenChange={setOpen}>
<ComboboxProvider open={open} setOpen={setOpen}>
<ComboboxLabel className="label">Your favorite fruit</ComboboxLabel>
<RadixPopover.Anchor asChild>
ref={comboboxRef}
placeholder="e.g., Apple, Banana"
className="combobox"
/>
</RadixPopover.Anchor>
<RadixPopover.Content
asChild
sideOffset={8}
onOpenAutoFocus={(event) => event.preventDefault()}
onInteractOutside={(event) => {
const target = event.target as Element | null;
const isCombobox = target === comboboxRef.current;
const inListbox = target && listboxRef.current?.contains(target);
if (isCombobox || inListbox) {
event.preventDefault();
}
}}
>
<ComboboxList ref={listboxRef} role="listbox" className="listbox">
<ComboboxItem focusOnHover className="option" value="Apple">
🍎 Apple
<ComboboxItem focusOnHover className="option" value="Grape">
🍇 Grape
<ComboboxItem focusOnHover className="option" value="Orange">
🍊 Orange
<ComboboxItem focusOnHover className="option" value="Strawberry">
🍓 Strawberry
<ComboboxItem focusOnHover className="option" value="Watermelon">
🍉 Watermelon
</RadixPopover.Content>
</RadixPopover.Root>
);
}

Components

Explore the Ariakit components used in this example:

Basic structure

<RadixPopover.Root>
<RadixPopover.Anchor asChild>
<Combobox />
</RadixPopover.Anchor>
<RadixPopover.Content asChild>
</RadixPopover.Content>
</RadixPopover.Root>

Sharing state between Ariakit and Radix UI

We can share state between Ariakit and Radix UI by passing our own open state to both Radix's Root and Ariakit's ComboboxProvider:

const [open, setOpen] = useState(false);
<RadixPopover.Root open={open} onOpenChange={setOpen}>
<ComboboxProvider open={open} setOpen={setOpen}>

You can learn more about this Ariakit feature in the guide:

Composing PopoverContent with ComboboxList

Rather than using the ComboboxPopover component from Ariakit, we can use the Radix PopoverContent in conjunction with the Ariakit ComboboxList component, which doesn't bundle popover features.

Here are a few things to keep in mind when assembling these components:

  1. 1

    A combobox typically doesn't auto-focus when it opens, so we need to stop the Radix onOpenAutoFocus event from performing its default behavior:

    <RadixPopover.Content
    onOpenAutoFocus={(event) => event.preventDefault()}
    >
  2. 2

    We need to stop Radix from closing the popover when interacting with the Combobox or any component within ComboboxList:

    <RadixPopover.Content
    onInteractOutside={(event) => {
    const isCombobox = comboboxElement === event.target;
    const inListbox = listboxElement?.contains(event.target);
    if (isCombobox || inListbox) {
    event.preventDefault();
    }
    }}
    >
  3. 3

    Finally, we must explicitly set role="listbox" on the ComboboxList component, otherwise Radix will overwrite it with role="dialog".

More examples

Stay tuned

Join 1,000+ subscribers and receive monthly tips & updates on new Ariakit content.

No spam. Unsubscribe anytime. Read latest issue