Skip to main content
Glama
combobox.md10.2 kB
# Catalyst Combobox Components - HTML & Tailwind CSS Examples This document provides HTML structure and Tailwind CSS class examples derived from the React-based Catalyst UI Kit's `Combobox`, `ComboboxOption`, `ComboboxLabel`, and `ComboboxDescription` components. These examples are intended for AI consumption and may need adaptation for specific projects or frameworks. These components are heavily reliant on Headless UI for functionality. ## Overview The Catalyst Combobox is a complex input control that combines a text input with a dropdown list of selectable options, allowing users to type to filter options or select from the list. It consists of: - `Combobox`: The main container, including the input field and the dropdown button. - `ComboboxOptions`: The floating panel that displays the list of selectable options. - `ComboboxOption`: An individual item within the options list. - `ComboboxLabel`: Used within a `ComboboxOption` for the primary display text. - `ComboboxDescription`: Used within a `ComboboxOption` for secondary, descriptive text. ## HTML Structure Example (Conceptual) This is a simplified conceptual HTML structure. A real implementation requires significant JavaScript for filtering, keyboard navigation, state management (open/closed, selected item, active item), ARIA attributes, and transitions, all of which Headless UI handles in the React version. ```html <!-- Combobox container (from Headless.Combobox) --> <div class="relative"> <!-- Control wrapper span (data-slot="control") --> <span class="relative block w-full before:absolute before:inset-px before:rounded-[calc(var(--radius-lg)-1px)] before:bg-white before:shadow-sm dark:before:hidden after:pointer-events-none after:absolute after:inset-0 after:rounded-lg after:ring-transparent after:ring-inset sm:focus-within:after:ring-2 sm:focus-within:after:ring-blue-500 ..."> <!-- Input field (Headless.ComboboxInput) --> <input type="text" aria-label="Assignee" placeholder="Select person..." class="relative block w-full appearance-none rounded-lg py-[calc(var(--spacing-2-5)-1px)] sm:py-[calc(var(--spacing-1-5)-1px)] pr-[calc(var(--spacing-10)-1px)] pl-[calc(var(--spacing-3-5)-1px)] sm:pr-[calc(var(--spacing-9)-1px)] sm:pl-[calc(var(--spacing-3)-1px)] text-base/6 text-zinc-950 placeholder:text-zinc-500 sm:text-sm/6 dark:text-white border border-zinc-950/10 data-hover:border-zinc-950/20 dark:border-white/10 dark:data-hover:border-white/20 bg-transparent dark:bg-white/5 focus:outline-hidden ..." /> <!-- Combobox Button (dropdown arrow) --> <button type="button" class="group absolute inset-y-0 right-0 flex items-center px-2"> <svg class="size-5 stroke-zinc-500 group-data-disabled:stroke-zinc-600 group-data-hover:stroke-zinc-700 sm:size-4 dark:stroke-zinc-400 dark:group-data-hover:stroke-zinc-300 forced-colors:stroke-[CanvasText]" viewBox="0 0 16 16" aria-hidden="true" fill="none"> <path d="M5.75 10.75L8 13L10.25 10.75" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /> <path d="M10.25 5.25L8 3L5.75 5.25" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /> </svg> </button> </span> <!-- Options Panel (Headless.ComboboxOptions) - shown/hidden by JS --> <div class="isolate min-w-[calc(var(--input-width)+8px)] scroll-py-1 rounded-xl p-1 select-none empty:invisible outline outline-transparent focus:outline-hidden overflow-y-scroll overscroll-contain bg-white/75 backdrop-blur-xl dark:bg-zinc-800/75 shadow-lg ring-1 ring-zinc-950/10 dark:ring-white/10 dark:ring-inset transition-opacity duration-100 ease-in data-closed:data-leave:opacity-0 ..." style="position: absolute; left: 0px; top: 100%; --anchor-gap:var(--spacing-2); ..."> <!-- Anchor positioning classes and style set by Headless UI --> <!-- ComboboxOption 1 --> <div class="group/option grid w-full cursor-default grid-cols-[1fr_var(--spacing-5)] items-baseline gap-x-2 rounded-lg py-2.5 pr-2 pl-3.5 sm:grid-cols-[1fr_var(--spacing-4)] sm:py-1.5 sm:pr-2 sm:pl-3 text-base/6 text-zinc-950 sm:text-sm/6 dark:text-white forced-colors:text-[CanvasText] outline-hidden data-focus:bg-blue-500 data-focus:text-white ..." role="option" tabindex="-1" aria-selected="false"> <span class="flex min-w-0 items-center ... (shared option classes) ..."> <!-- Optional icon/avatar --> <span data-slot="label" class="ml-2.5 truncate first:ml-0 sm:ml-2 sm:first:ml-0">Option Text 1</span> <span class="flex flex-1 overflow-hidden text-zinc-500 group-data-focus/option:text-white before:w-2 before:min-w-0 before:shrink dark:text-zinc-400"> <span data-slot="description" class="flex-1 truncate">Description for option 1</span> </span> </span> <svg class="relative col-start-2 hidden size-5 self-center stroke-current group-data-selected/option:inline sm:size-4" viewBox="0 0 16 16" fill="none" aria-hidden="true"> <path d="M4 8.5l3 3L12 4" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /> </svg> </div> <!-- More ComboboxOption elements... --> </div> </div> ``` ## Tailwind CSS Classes ### `Combobox` - Outer Control Wrapper (`<span data-slot="control">`) ```plaintext relative block w-full before:absolute before:inset-px before:rounded-[calc(var(--radius-lg)-1px)] before:bg-white before:shadow-sm dark:before:hidden after:pointer-events-none after:absolute after:inset-0 after:rounded-lg after:ring-transparent after:ring-inset sm:focus-within:after:ring-2 sm:focus-within:after:ring-blue-500 has-data-disabled:opacity-50 has-data-disabled:before:bg-zinc-950/5 has-data-disabled:before:shadow-none has-data-invalid:before:shadow-red-500/10 ``` ### `ComboboxInput` (`<input>`) ```plaintext relative block w-full appearance-none rounded-lg py-[calc(var(--spacing-2-5)-1px)] sm:py-[calc(var(--spacing-1-5)-1px)] pr-[calc(var(--spacing-10)-1px)] pl-[calc(var(--spacing-3-5)-1px)] sm:pr-[calc(var(--spacing-9)-1px)] sm:pl-[calc(var(--spacing-3)-1px)] text-base/6 text-zinc-950 placeholder:text-zinc-500 sm:text-sm/6 dark:text-white border border-zinc-950/10 data-hover:border-zinc-950/20 dark:border-white/10 dark:data-hover:border-white/20 bg-transparent dark:bg-white/5 focus:outline-hidden data-invalid:border-red-500 data-invalid:data-hover:border-red-500 dark:data-invalid:border-red-500 dark:data-invalid:data-hover:border-red-500 data-disabled:border-zinc-950/20 dark:data-disabled:border-white/15 dark:data-disabled:bg-white/[2.5%] dark:data-hover:data-disabled:border-white/15 dark:scheme-dark ``` ### `ComboboxButton` (Dropdown Arrow `<button>`) ```plaintext group absolute inset-y-0 right-0 flex items-center px-2 ``` SVG inside button: ```plaintext size-5 stroke-zinc-500 group-data-disabled:stroke-zinc-600 group-data-hover:stroke-zinc-700 sm:size-4 dark:stroke-zinc-400 dark:group-data-hover:stroke-zinc-300 forced-colors:stroke-[CanvasText] ``` ### `ComboboxOptions` (Dropdown Panel `<div>`) ```plaintext [--anchor-gap:var(--spacing-2)] [--anchor-padding:var(--spacing-4)] sm:data-[anchor~=start]:[--anchor-offset:-4px] isolate min-w-[calc(var(--input-width)+8px)] scroll-py-1 rounded-xl p-1 select-none empty:invisible outline outline-transparent focus:outline-hidden overflow-y-scroll overscroll-contain bg-white/75 backdrop-blur-xl dark:bg-zinc-800/75 shadow-lg ring-1 ring-zinc-950/10 dark:ring-white/10 dark:ring-inset transition-opacity duration-100 ease-in data-closed:data-leave:opacity-0 data-transition:pointer-events-none ``` - Anchor positioning classes (e.g., `[--anchor-gap:...]`) are used by Headless UI's positioning logic. ### `ComboboxOption` (`<div>`) Base classes for each option: ```plaintext group/option grid w-full cursor-default grid-cols-[1fr_var(--spacing-5)] items-baseline gap-x-2 rounded-lg py-2.5 pr-2 pl-3.5 sm:grid-cols-[1fr_var(--spacing-4)] sm:py-1.5 sm:pr-2 sm:pl-3 text-base/6 text-zinc-950 sm:text-sm/6 dark:text-white forced-colors:text-[CanvasText] outline-hidden data-focus:bg-blue-500 data-focus:text-white forced-color-adjust-none forced-colors:data-focus:bg-[Highlight] forced-colors:data-focus:text-[HighlightText] data-disabled:opacity-50 ``` Shared classes for content wrapper span inside option: ```plaintext flex min-w-0 items-center *:data-[slot=icon]:size-5 *:data-[slot=icon]:shrink-0 sm:*:data-[slot=icon]:size-4 *:data-[slot=icon]:text-zinc-500 group-data-focus/option:*:data-[slot=icon]:text-white dark:*:data-[slot=icon]:text-zinc-400 forced-colors:*:data-[slot=icon]:text-[CanvasText] forced-colors:group-data-focus/option:*:data-[slot=icon]:text-[Canvas] *:data-[slot=avatar]:-mx-0.5 *:data-[slot=avatar]:size-6 sm:*:data-[slot=avatar]:size-5 ``` Selected checkmark SVG (inside option): ```plaintext relative col-start-2 hidden size-5 self-center stroke-current group-data-selected/option:inline sm:size-4 ``` ### `ComboboxLabel` (`<span>`) ```plaintext ml-2.5 truncate first:ml-0 sm:ml-2 sm:first:ml-0 ``` ### `ComboboxDescription` (`<span>`) Outer span: ```plaintext flex flex-1 overflow-hidden text-zinc-500 group-data-focus/option:text-white before:w-2 before:min-w-0 before:shrink dark:text-zinc-400 ``` Inner span for truncation: ```plaintext flex-1 truncate ``` ## Notes for Usage * **Heavy JavaScript Dependence:** This component is highly interactive and relies almost entirely on JavaScript (Headless UI) for its behavior, including option filtering, keyboard navigation, ARIA attributes, managing open/closed states, and handling selection. The HTML and CSS provide the appearance. * **Data Attributes:** State-based styling (focus, disabled, selected, invalid, open/closed) is driven by data attributes set by Headless UI. * **CSS Variables:** Uses Catalyst-specific CSS variables (e.g., `var(--radius-lg)`, `var(--spacing-...)`). These would need to be defined in a global stylesheet or replaced. * **Render Props:** The React component uses render props for `children` in `Combobox` and `ComboboxOptions`, allowing flexible rendering of options. This is a React pattern. This Markdown file provides the HTML structure and class details from Catalyst's Combobox components for analysis and adaptation.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/CaullenOmdahl/Tailwind-Svelte-Assistant'

If you have feedback or need assistance with the MCP directory API, please join our Discord server