Marigold
Marigold

Application

MarigoldProvider
RouterProvider

Layout

AppLayoutbeta
Aside
Aspect
Breakout
Center
Columns
Container
Grid
Inline
Inset
Scrollable
Split
Stack
Tiles

Actions

ActionBaralpha
Button
Link
LinkButton
ToggleButtonalpha
ToggleButtonGroupalpha

Form

Autocomplete
Calendarupdated
Checkbox
ComboBox
DateField
DatePicker
FileField
Form
Multiselectdeprecated
NumberField
Radio
SearchField
Select
Slider
Switch
TagFieldbeta
TextArea
TextField
TimeField

Collection

SelectList
Tableupdated
Tag

Navigation

Accordion
Breadcrumbs
Pagination
Sidebarbeta
Tabs
TopNavigationbeta

Overlay

ContextualHelp
Dialog
Drawer
Menu
Toastbeta
Tooltip

Content

Badge
Card
Divider
EmptyStatebeta
Headline
Icon
List
Loader
SectionMessage
SVG
Text

Formatters

DateFormat
NumericFormat

Hooks and Utils

cn
cva
extendTheme
parseFormData
useAsyncListData
useListData
useResponsiveValue
useTheme
VisuallyHidden
Components

ComboBox

A text-field that allows the user to select values from a provided items array.

The <ComboBox> component combines a text input with a listbox, allowing users to filter a list of options to items matching a query or adding a new value.

Its purpose is to make interaction with software more intuitive by presenting options in a concise, readable manner instead of requiring users to remember cryptic commands or navigate through complex hierarchies

Appearance

The appearance of a component can be customized using the variant and size props. These props adjust the visual style and dimensions of the component, available values are based on the active theme.

The selected theme does not has any options for"variant" and "size".
PropertyTypeDescription
variant-The available variants of this component.
size-The available sizes of this component.

Usage

Controlled Usage with custom Filter

If you want to listen or act while the user is typing into the ComboBox field, you can switch to controlled mode by adding an onChange handler and setting the value manually.

This is especially helpful if you need to customize the filtering. For example, you may only want to show suggestions when the user has typed at least two characters. Furthermore, you can improve the matching, as shown in the example below. In the demo, the user would not receive a suggestion if they typed "ssp" without the custom filter.

currentValue: ""
import { useState } from 'react';import { ComboBox, Stack, Text } from '@marigold/components';export default () => {  const [currentValue, setCurrentValue] = useState<string | undefined>();  return (    <Stack>      <ComboBox        value={currentValue}        onChange={setCurrentValue}        defaultSelectedKey={3}        label="Animals"      >        <ComboBox.Option id="red panda">Red Panda</ComboBox.Option>        <ComboBox.Option id="cat">Cat</ComboBox.Option>        <ComboBox.Option id="dog">Dog</ComboBox.Option>        <ComboBox.Option id="aardvark">Aardvark</ComboBox.Option>        <ComboBox.Option id="kangaroo">Kangaroo</ComboBox.Option>      </ComboBox>      <Text weight="black">currentValue: "{currentValue}"</Text>    </Stack>  );};

With sections

When related options are present, organizing them into sections enhances clarity and usability. Grouping options provides additional context and helps users navigate choices more easily. This approach reduces complexity and allows for additional guidance when needed, ensuring a more intuitive experience.

This can be achieved by wrapping the options in the <ComboBox.Section> component. A header is required for each section, which is set using the header prop. It's important to note that headers are not part of the accessibility tree. As a result, they will not be considered when filtering the option list.

When `textValue` is required

Use the textValue prop when children contain non-text elements (e.g., icons, badges, or other decorative components) - this ensures search functions revieve plain text equivalents, as non-text elements can create mismatches between visual and semantic content.

import { ComboBox, Text } from '@marigold/components';export default () => (  <ComboBox label="Genres" width="fit">    {options.map(item => (      <ComboBox.Section key={item.category} header={item.category}>        {item.genres.map(genre => (          <ComboBox.Option            key={genre.name}            id={genre.id}            textValue={genre.name}          >            <Text slot="label">{genre.name}</Text>            <Text slot="description">{genre.description}</Text>          </ComboBox.Option>        ))}      </ComboBox.Section>    ))}  </ComboBox>);const options = [  {    category: 'Pop and Dance',    genres: [      {        id: 'pop',        name: 'Pop',        description: 'Catchy, upbeat music with mass appeal',      },      {        id: 'synth-pop',        name: 'Synth-pop',        description: 'Synthesizer-driven pop music from the 80s',      },      {        id: 'electropop',        name: 'Electropop',        description: 'Electronic pop with heavy digital production',      },      {        id: 'dance-pop',        name: 'Dance-pop',        description: 'Upbeat pop music designed for dancing',      },      {        id: 'teen-pop',        name: 'Teen pop',        description: 'Youth-oriented pop music with catchy hooks',      },      {        id: 'disco',        name: 'Disco',        description: 'Dance-oriented 70s music with orchestral arrangements',      },    ],  },  {    category: 'Rock and Alternative',    genres: [      {        id: 'rock',        name: 'Rock',        description: 'Guitar-driven music with strong rhythms',      },      {        id: 'hard-rock',        name: 'Hard rock',        description: 'Heavier, more aggressive rock style',      },      {        id: 'punk-rock',        name: 'Punk rock',        description: 'Raw, fast-paced music with anti-establishment themes',      },      {        id: 'alternative-rock',        name: 'Alternative rock',        description: 'Non-mainstream rock emerging from indie scenes',      },      {        id: 'indie-rock',        name: 'Indie rock',        description: 'Independent-label rock with DIY ethos',      },      {        id: 'grunge',        name: 'Grunge',        description: 'Raw, distorted sound from the Seattle scene',      },      {        id: 'psychedelic-rock',        name: 'Psychedelic rock',        description: 'Mind-altering rock with experimental sounds',      },    ],  },  {    category: 'Hip-Hop and R&B',    genres: [      {        id: 'hip-hop',        name: 'Hip-Hop',        description: 'Urban music with rhythmic beats and rhyming speech',      },      {        id: 'rap',        name: 'Rap',        description: 'Rhythmic vocal style over beat-driven backing',      },      {        id: 'trap',        name: 'Trap',        description: 'Southern hip-hop with heavy bass and hi-hats',      },      {        id: 'r&b',        name: 'R&B',        description: 'Rhythm and blues combining soul and pop elements',      },      {        id: 'neo-soul',        name: 'Neo-soul',        description: 'Modern soul music with hip-hop influences',      },    ],  },  {    category: 'Electronic and Experimental',    genres: [      {        id: 'edm',        name: 'EDM',        description: 'Electronic Dance Music for festival crowds',      },      {        id: 'house',        name: 'House',        description: 'Repetitive 4/4 beats with synth basslines',      },      {        id: 'techno',        name: 'Techno',        description: 'Minimal electronic music with mechanical rhythms',      },      {        id: 'dubstep',        name: 'Dubstep',        description: 'Bass-heavy electronic music with wobble effects',      },      {        id: 'ambient',        name: 'Ambient',        description: 'Atmospheric, texture-based electronic soundscapes',      },      {        id: 'industrial',        name: 'Industrial',        description: 'Harsh electronic sounds mixed with punk elements',      },    ],  },  {    category: 'Jazz and Blues',    genres: [      {        id: 'jazz',        name: 'Jazz',        description: 'Improvisational music with swing and blue notes',      },      {        id: 'smooth-jazz',        name: 'Smooth Jazz',        description: 'Polished, radio-friendly jazz style',      },      {        id: 'bebop',        name: 'Bebop',        description: 'Complex, fast-tempo jazz improvisation',      },      {        id: 'blues',        name: 'Blues',        description: 'Soulful music based on blues scales and patterns',      },      {        id: 'delta-blues',        name: 'Delta Blues',        description: 'Acoustic blues from the Mississippi Delta',      },      {        id: 'chicago-blues',        name: 'Chicago Blues',        description: 'Electric blues with amplified instruments',      },    ],  },  {    category: 'Classical and Orchestral',    genres: [      {        id: 'classical',        name: 'Classical',        description: 'Traditional Western art music',      },      {        id: 'baroque',        name: 'Baroque',        description: 'Ornate style from 1600-1750 with harpsichords',      },      {        id: 'opera',        name: 'Opera',        description: 'Dramatic stage works combining music and theater',      },      {        id: 'symphony',        name: 'Symphony',        description: 'Large-scale orchestral compositions',      },      {        id: 'chamber-music',        name: 'Chamber Music',        description: 'Classical music for small ensembles',      },    ],  },  {    category: 'Folk and Country',    genres: [      {        id: 'folk',        name: 'Folk',        description: 'Traditional music with acoustic instrumentation',      },      {        id: 'country',        name: 'Country',        description: 'Storytelling music with roots in rural America',      },      {        id: 'bluegrass',        name: 'Bluegrass',        description: 'Fast-paced acoustic music with banjo and fiddle',      },      {        id: 'americana',        name: 'Americana',        description: 'Blend of country, folk, and roots music',      },    ],  },  {    category: 'Latin and World',    genres: [      {        id: 'reggaeton',        name: 'Reggaeton',        description: 'Puerto Rican blend of reggae and Latin rhythms',      },      {        id: 'salsa',        name: 'Salsa',        description: 'Energetic Cuban-derived dance music',      },      {        id: 'bossa-nova',        name: 'Bossa Nova',        description: 'Brazilian jazz-samba fusion with smooth rhythms',      },      {        id: 'flamenco',        name: 'Flamenco',        description: 'Passionate Spanish music with guitar and dance',      },      {        id: 'afrobeats',        name: 'Afrobeats',        description: 'West African pop music with complex rhythms',      },    ],  },  {    category: 'Metal and Hard Music',    genres: [      {        id: 'heavy-metal',        name: 'Heavy Metal',        description: 'Loud, aggressive music with distorted guitars',      },      {        id: 'thrash-metal',        name: 'Thrash Metal',        description: 'Fast, technical metal with punk influences',      },      {        id: 'death-metal',        name: 'Death Metal',        description: 'Extreme metal with growled vocals and blast beats',      },      {        id: 'doom-metal',        name: 'Doom Metal',        description: 'Slow, heavy metal with dark atmospheres',      },    ],  },  {    category: 'Reggae and Caribbean',    genres: [      {        id: 'reggae',        name: 'Reggae',        description: 'Jamaican music with offbeat rhythms',      },      {        id: 'ska',        name: 'Ska',        description: 'Jamaican precursor to reggae with walking bassline',      },      {        id: 'dancehall',        name: 'Dancehall',        description: 'Digital reggae style with rapid lyrical delivery',      },      {        id: 'soca',        name: 'Soca',        description: 'Upbeat Caribbean dance music from Trinidad',      },    ],  },];

Working with asynchronous Data

The ComboBox component supports working with asynchronous data. In the example below, the useAsyncList hook is used to handle the loading and filtering of data from the server.

import { ComboBox, useAsyncList } from '@marigold/components';export default () => {  const list = useAsyncList<{ name: string }>({    async load({ signal, filterText }) {      const res = await fetch(        `https://swapi.py4e.com/api/people/?search=${filterText}`,        {          signal,        }      );      const json = await res.json();      return {        items: json.results,      };    },  });  return (    <ComboBox      label="Star Wars Character Lookup"      value={list.filterText}      onChange={list.setFilterText}      items={list.items}    >      {(item: { name: string }) => (        <ComboBox.Option id={item.name}>{item.name}</ComboBox.Option>      )}    </ComboBox>  );};

Displaying Suggestions

Opening the suggestion popover can be triggered through various interactions. This behavior can be adjusted by the menuTrigger prop:

  • input (default): Open when the user edits the input text.
  • focus: Open when the user focuses the <ComboBox> input.
  • manual: Open when the user presses the trigger button or uses the arrow keys.

The below examples will display the suggestions when the input field is focused.

import { ComboBox } from '@marigold/components';export default () => (  <ComboBox label="Animals" menuTrigger="focus">    <ComboBox.Option id="red panda">Red Panda</ComboBox.Option>    <ComboBox.Option id="cat">Cat</ComboBox.Option>    <ComboBox.Option id="dog">Dog</ComboBox.Option>    <ComboBox.Option id="aardvark">Aardvark</ComboBox.Option>    <ComboBox.Option id="kangaroo">Kangaroo</ComboBox.Option>    <ComboBox.Option id="snake">Snake</ComboBox.Option>    <ComboBox.Option id="vegan">Vegan</ComboBox.Option>    <ComboBox.Option id="mar">Margrita</ComboBox.Option>  </ComboBox>);

Item Actions

The <ComboBox.Option> component supports an onAction prop that triggers a callback when the user performs an action on an item. This is useful for triggering side effects such as navigating to a detail view or opening an edit modal.

By combining controlled input (value/onChange) with allowsCustomValue and a conditional <ComboBox.Option>, you can offer a dynamic "Create new" option that reflects what the user has typed. This is a common pattern for comboboxes that allow creating new entries inline.

`onAction` vs `onSelectionChange`

The onAction prop on individual options differs from the onSelectionChange prop on the <ComboBox> itself. Use onSelectionChange when you need to track and manage the selected value. Use onAction when you need to perform a side effect when an item is activated, regardless of selection state. Note that onAction should not replace the primary selection behavior - it is intended for supplementary actions.

Selected:
None
Last action:
None
import { useState } from 'react';import { ComboBox, Stack, Text } from '@marigold/components';export default () => {  const [lastAction, setLastAction] = useState<string | null>(null);  const [selectedKey, setSelectedKey] = useState<string | null>(null);  return (    <Stack space={4}>      <ComboBox        label="Projects"        menuTrigger="focus"        onSelectionChange={key => setSelectedKey(key as string)}      >        <ComboBox.Section key="actions" header="Actions">          <ComboBox.Option            id="new"            onAction={() => setLastAction('Create new file...')}          >            New file          </ComboBox.Option>          <ComboBox.Option            id="open"            onAction={() =>              setLastAction(`Opening details for file ${selectedKey}...`)            }          >            Open          </ComboBox.Option>        </ComboBox.Section>        <ComboBox.Section key="files" header="Files">          <ComboBox.Option id="file-1">            Top Secret - RUI Initative          </ComboBox.Option>          <ComboBox.Option id="file-2">Tech Radar</ComboBox.Option>          <ComboBox.Option id="file-3">Who is Claude?</ComboBox.Option>        </ComboBox.Section>      </ComboBox>      <Text weight="black">Selected:</Text> {selectedKey ?? 'None'}      <Text weight="black">Last action:</Text> {lastAction ?? 'None'}    </Stack>  );};

Props

Did you know? You can explore, test, and customize props live in Marigold's storybook. Watch the effects they have in real-time!
View ComboBox stories

ComboBox

Prop

Type

ComboBox.Option

Prop

Type

ComboBox.Section

Prop

Type

Last update: 10 days ago

Checkbox

Component to select one or more options.

DateField

Component for entering date in forms.

On this page

AppearanceUsageControlled Usage with custom FilterWith sectionsWorking with asynchronous DataDisplaying SuggestionsItem ActionsPropsComboBoxComboBox.OptionComboBox.Section