Brik Design System
Components

Addable combo list

Suggestion-driven combobox for tag-style multi-select with free-form fallback.

AddableComboList is the vocabulary-backed sibling of AddableTextList. Typing filters a known suggestion list (case-insensitive contains match); users can pick from suggestions via keyboard/click, or type a free-form value and press Enter (unless strict).

Use for intake fields where a vocabulary exists but editors may need custom entries — services offered, payment types, insurance providers wired from BCS getters like getIndustryServices.

AddableComboList

Use when: Vocabulary-backed picks with optional free-form fallback. BCS getters, locked enums.

Don't: No vocabulary — use AddableTextList.

<AddableComboList suggestions={...} />

AddableTextList

Use when: Free-form one-string-per-row entry, no vocabulary.

Don't: Vocabulary exists — use ComboList for autocomplete.

<AddableTextList values={...} />

MultiSelect

Use when: Locked vocabulary, no free-form. Renders as Tag chips.

Don't: Need free-form fallback — use ComboList with strict=false.

<MultiSelect options={...} />

Use it for

  • Services from a BCS catalog with the option to add custom ones
  • Payment types / insurance providers where the industry pack seeds defaults but clients may add specifics
  • Tag entry against a recent-tags suggestion list

Import

import { AddableComboList } from '@brikdesigns/bds';
import { getIndustryServices } from '@brikdesigns/bds/content-system';

Variants

Default — vocabulary-backed

import { useState } from 'react';
const [values, setValues] = useState<string[]>([]);
const services = getIndustryServices(company.industry_slug);

<AddableComboList
  label="Services offered"
  values={values}
  onChange={setValues}
  suggestions={services}
  placeholder="Type or pick a service…"
/>

Strict mode — vocabulary-only

When strict is true, only suggestions can be added. Free-form Enter is blocked and a hint shows while the typed value doesn't match any suggestion.

<AddableComboList
  label="Insurance accepted"
  values={values}
  onChange={setValues}
  suggestions={INSURANCE_PROVIDERS}
  strict
/>

Sizes

sm, md (default), lg.

Disabled

Renders tags without input or remove controls.

<AddableComboList values={values} onChange={() => {}} suggestions={[]} disabled />

Max entries

When maxEntries is reached, the add button is hidden.

<AddableComboList
  values={values}
  onChange={setValues}
  suggestions={services}
  maxEntries={5}
/>

Behavior

  • Typing filters suggestions (case-insensitive contains) and opens the dropdown.
  • Arrow keys cycle through dropdown options.
  • Enter with a highlighted suggestion commits it; Enter with no highlight commits the raw typed string (unless strict).
  • Esc closes the dropdown (first press) or cancels the input (second press).
  • Backspace on empty input removes the last tag.
  • Already-selected suggestions are hidden from the dropdown.
  • Duplicates trigger a brief flash outline and are not added.

When not to use

Don't use AddableComboList when there's no vocabulary. Free-form-only is AddableTextList's job — the combobox dropdown adds visual weight that goes nowhere without suggestions.

  • Don't use for locked vocabularies with no free-form escape. Use MultiSelect — same Tag-chip output, simpler for users (just pick).
  • Don't use for description-bearing entries. Each row is one short string. Title + description belongs in AddableEntryList.

Accessibility

  • Input: role="combobox", aria-expanded, aria-haspopup="listbox", aria-activedescendant
  • Dropdown: role="listbox" with role="option" items and aria-selected
  • Tags: role="list" / role="listitem" with accessible labels
  • Screen reader announce on add/remove via aria-live on the tag container

API

PropTypeDefault
valuesstring[] (required)
onChange(next: string[]) => void (required)
suggestionsstring[] (required)
labelstring
helperTextstring
placeholderstring
addLabelstring'Add'
removeLabelstring'Remove'
emptyLabelstring
size'sm' | 'md' | 'lg''md'
disabledbooleanfalse
maxEntriesnumberunlimited
strictbooleanfalse

On this page