Combobox

A searchable text field with authored <option> suggestions.

Label and options

Native option elements provide the ordinary no-script option list.

Code

<link
  rel="component"
  href="@threadlabs/looma/components/ui-combobox/ui-combobox.html"
>

<ui-combobox
  label="Destination"
  disclosure
>
  <option
    value="north"
    data-description="Harbor district"
  >North terminal</option>
  <option
    value="west"
    data-description="Riverside"
  >West terminal</option>
</ui-combobox>
<script setup>
  import { UiCombobox } from "@threadlabs/looma";
</script>

<template>
  <UiCombobox
    label="Destination"
    :disclosure="true"
  >
    <option
      value="north"
      data-description="Harbor district"
    >North terminal</option>
    <option
      value="west"
      data-description="Riverside"
    >West terminal</option>
  </UiCombobox>
</template>
import { UiCombobox } from "@threadlabs/looma";

export default function Example() {
  return <UiCombobox
    label="Destination"
    disclosure
  >
    <option
      value="north"
      data-description="Harbor district"
    >North terminal</option>
    <option
      value="west"
      data-description="Riverside"
    >West terminal</option>
  </UiCombobox>;
}
/** @jsxImportSource preact */
import { UiCombobox } from "@threadlabs/looma";

export default function Example() {
  return <UiCombobox
    label="Destination"
    disclosure
  >
    <option
      value="north"
      data-description="Harbor district"
    >North terminal</option>
    <option
      value="west"
      data-description="Riverside"
    >West terminal</option>
  </UiCombobox>;
}
<script>
  import { UiCombobox } from "@threadlabs/looma";
</script>

<UiCombobox
  label="Destination"
  disclosure
>
  <option
    value="north"
    data-description="Harbor district"
  >North terminal</option>
  <option
    value="west"
    data-description="Riverside"
  >West terminal</option>
</UiCombobox>
import { Component } from "@angular/core";
import { UiCombobox } from "@threadlabs/looma";

@Component({
  selector: "example-view",
  standalone: true,
  imports: [UiCombobox],
  template: `
    <div
      ui-combobox
      [label]="'Destination'"
      [disclosure]="true"
    >
      <option
        value="north"
        data-description="Harbor district"
      >North terminal</option>
      <option
        value="west"
        data-description="Riverside"
      >West terminal</option>
    </div>
  `,
})
export default class Example {}

Disclosure, clearable, and size

Disclosure adds the toggle, clearable adds value removal, and size controls field density.

Code

<link
  rel="component"
  href="@threadlabs/looma/components/ui-combobox/ui-combobox.html"
>

<ui-combobox
  label="Destination"
  disclosure
  clearable
  allow-free-text
  allow-create
  size="sm"
  placeholder="Search…"
>
  <option
    value="north"
  >North terminal</option>
  <option
    value="west"
  >West terminal</option>
</ui-combobox>
<script setup>
  import { UiCombobox } from "@threadlabs/looma";
</script>

<template>
  <UiCombobox
    label="Destination"
    :disclosure="true"
    :clearable="true"
    :allow-free-text="true"
    :allow-create="true"
    size="sm"
    placeholder="Search…"
  >
    <option
      value="north"
    >North terminal</option>
    <option
      value="west"
    >West terminal</option>
  </UiCombobox>
</template>
import { UiCombobox } from "@threadlabs/looma";

export default function Example() {
  return <UiCombobox
    label="Destination"
    disclosure
    clearable
    allowFreeText
    allowCreate
    size="sm"
    placeholder="Search…"
  >
    <option
      value="north"
    >North terminal</option>
    <option
      value="west"
    >West terminal</option>
  </UiCombobox>;
}
/** @jsxImportSource preact */
import { UiCombobox } from "@threadlabs/looma";

export default function Example() {
  return <UiCombobox
    label="Destination"
    disclosure
    clearable
    allowFreeText
    allowCreate
    size="sm"
    placeholder="Search…"
  >
    <option
      value="north"
    >North terminal</option>
    <option
      value="west"
    >West terminal</option>
  </UiCombobox>;
}
<script>
  import { UiCombobox } from "@threadlabs/looma";
</script>

<UiCombobox
  label="Destination"
  disclosure
  clearable
  allowFreeText
  allowCreate
  size="sm"
  placeholder="Search…"
>
  <option
    value="north"
  >North terminal</option>
  <option
    value="west"
  >West terminal</option>
</UiCombobox>
import { Component } from "@angular/core";
import { UiCombobox } from "@threadlabs/looma";

@Component({
  selector: "example-view",
  standalone: true,
  imports: [UiCombobox],
  template: `
    <div
      ui-combobox
      [label]="'Destination'"
      [disclosure]="true"
      [clearable]="true"
      [allowFreeText]="true"
      [allowCreate]="true"
      [size]="'sm'"
      [placeholder]="'Search…'"
    >
      <option
        value="north"
      >North terminal</option>
      <option
        value="west"
      >West terminal</option>
    </div>
  `,
})
export default class Example {}

multiple

Multiple collects several selections in one scrolling field row. With name, a form submits one entry per chosen item's value (here teams=design, teams=docs), never the labels.

Code

<link
  rel="component"
  href="@threadlabs/looma/components/ui-combobox/ui-combobox.html"
>

<ui-combobox
  label="Teams"
  name="teams"
  multiple
  disclosure
  placeholder="Add a team…"
>
  <option
    value="design"
    selected
  >Design</option>
  <option
    value="docs"
    selected
  >Docs</option>
  <option
    value="platform"
  >Platform</option>
</ui-combobox>
<script setup>
  import { UiCombobox } from "@threadlabs/looma";
</script>

<template>
  <UiCombobox
    label="Teams"
    name="teams"
    :multiple="true"
    :disclosure="true"
    placeholder="Add a team…"
  >
    <option
      value="design"
      selected
    >Design</option>
    <option
      value="docs"
      selected
    >Docs</option>
    <option
      value="platform"
    >Platform</option>
  </UiCombobox>
</template>
import { UiCombobox } from "@threadlabs/looma";

export default function Example() {
  return <UiCombobox
    label="Teams"
    name="teams"
    multiple
    disclosure
    placeholder="Add a team…"
  >
    <option
      value="design"
      selected
    >Design</option>
    <option
      value="docs"
      selected
    >Docs</option>
    <option
      value="platform"
    >Platform</option>
  </UiCombobox>;
}
/** @jsxImportSource preact */
import { UiCombobox } from "@threadlabs/looma";

export default function Example() {
  return <UiCombobox
    label="Teams"
    name="teams"
    multiple
    disclosure
    placeholder="Add a team…"
  >
    <option
      value="design"
      selected
    >Design</option>
    <option
      value="docs"
      selected
    >Docs</option>
    <option
      value="platform"
    >Platform</option>
  </UiCombobox>;
}
<script>
  import { UiCombobox } from "@threadlabs/looma";
</script>

<UiCombobox
  label="Teams"
  name="teams"
  multiple
  disclosure
  placeholder="Add a team…"
>
  <option
    value="design"
    selected
  >Design</option>
  <option
    value="docs"
    selected
  >Docs</option>
  <option
    value="platform"
  >Platform</option>
</UiCombobox>
import { Component } from "@angular/core";
import { UiCombobox } from "@threadlabs/looma";

@Component({
  selector: "example-view",
  standalone: true,
  imports: [UiCombobox],
  template: `
    <div
      ui-combobox
      [label]="'Teams'"
      [name]="'teams'"
      [multiple]="true"
      [disclosure]="true"
      [placeholder]="'Add a team…'"
    >
      <option
        value="design"
        selected
      >Design</option>
      <option
        value="docs"
        selected
      >Docs</option>
      <option
        value="platform"
      >Platform</option>
    </div>
  `,
})
export default class Example {}

help and label-visibility="sr-only"

Help adds a hint button with a tooltip; label-visibility keeps the label for assistive technology while hiding it visually.

Code

<link
  rel="component"
  href="@threadlabs/looma/components/ui-combobox/ui-combobox.html"
>

<ui-combobox
  label="Destination"
  label-visibility="sr-only"
  help="Pick where the shipment should be delivered."
  disclosure
  placeholder="Destination"
>
  <option
    value="north"
  >North terminal</option>
  <option
    value="west"
  >West terminal</option>
</ui-combobox>
<script setup>
  import { UiCombobox } from "@threadlabs/looma";
</script>

<template>
  <UiCombobox
    label="Destination"
    label-visibility="sr-only"
    help="Pick where the shipment should be delivered."
    :disclosure="true"
    placeholder="Destination"
  >
    <option
      value="north"
    >North terminal</option>
    <option
      value="west"
    >West terminal</option>
  </UiCombobox>
</template>
import { UiCombobox } from "@threadlabs/looma";

export default function Example() {
  return <UiCombobox
    label="Destination"
    labelVisibility="sr-only"
    help="Pick where the shipment should be delivered."
    disclosure
    placeholder="Destination"
  >
    <option
      value="north"
    >North terminal</option>
    <option
      value="west"
    >West terminal</option>
  </UiCombobox>;
}
/** @jsxImportSource preact */
import { UiCombobox } from "@threadlabs/looma";

export default function Example() {
  return <UiCombobox
    label="Destination"
    labelVisibility="sr-only"
    help="Pick where the shipment should be delivered."
    disclosure
    placeholder="Destination"
  >
    <option
      value="north"
    >North terminal</option>
    <option
      value="west"
    >West terminal</option>
  </UiCombobox>;
}
<script>
  import { UiCombobox } from "@threadlabs/looma";
</script>

<UiCombobox
  label="Destination"
  labelVisibility="sr-only"
  help="Pick where the shipment should be delivered."
  disclosure
  placeholder="Destination"
>
  <option
    value="north"
  >North terminal</option>
  <option
    value="west"
  >West terminal</option>
</UiCombobox>
import { Component } from "@angular/core";
import { UiCombobox } from "@threadlabs/looma";

@Component({
  selector: "example-view",
  standalone: true,
  imports: [UiCombobox],
  template: `
    <div
      ui-combobox
      [label]="'Destination'"
      [labelVisibility]="'sr-only'"
      [help]="'Pick where the shipment should be delivered.'"
      [disclosure]="true"
      [placeholder]="'Destination'"
    >
      <option
        value="north"
      >North terminal</option>
      <option
        value="west"
      >West terminal</option>
    </div>
  `,
})
export default class Example {}

readonly, disabled, and required

Readonly shows a value that cannot change, disabled makes the field unavailable, and required participates in form validation. A named combobox submits the chosen option's value, such as destination=north, not its label.

Code

<link
  rel="component"
  href="@threadlabs/looma/components/ui-stack/ui-stack.html"
>
<link
  rel="component"
  href="@threadlabs/looma/components/ui-combobox/ui-combobox.html"
>

<ui-stack
  gap="s"
>
  <ui-combobox
    label="Readonly"
    readonly
    value="north"
    disclosure
  >
    <option
      value="north"
    >North terminal</option>
  </ui-combobox>
  <ui-combobox
    label="Disabled"
    disabled
    disclosure
  >
    <option
      value="north"
    >North terminal</option>
  </ui-combobox>
  <ui-combobox
    label="Required"
    name="destination"
    required
    disclosure
  >
    <option
      value="north"
    >North terminal</option>
    <option
      value="west"
    >West terminal</option>
  </ui-combobox>
</ui-stack>
<script setup>
  import { UiCombobox, UiStack } from "@threadlabs/looma";
</script>

<template>
  <UiStack
    gap="s"
  >
    <UiCombobox
      label="Readonly"
      :readonly="true"
      value="north"
      :disclosure="true"
    >
      <option
        value="north"
      >North terminal</option>
    </UiCombobox>
    <UiCombobox
      label="Disabled"
      :disabled="true"
      :disclosure="true"
    >
      <option
        value="north"
      >North terminal</option>
    </UiCombobox>
    <UiCombobox
      label="Required"
      name="destination"
      :required="true"
      :disclosure="true"
    >
      <option
        value="north"
      >North terminal</option>
      <option
        value="west"
      >West terminal</option>
    </UiCombobox>
  </UiStack>
</template>
import { UiCombobox, UiStack } from "@threadlabs/looma";

export default function Example() {
  return <UiStack
    gap="s"
  >
    <UiCombobox
      label="Readonly"
      readOnly
      value="north"
      disclosure
    >
      <option
        value="north"
      >North terminal</option>
    </UiCombobox>
    <UiCombobox
      label="Disabled"
      disabled
      disclosure
    >
      <option
        value="north"
      >North terminal</option>
    </UiCombobox>
    <UiCombobox
      label="Required"
      name="destination"
      required
      disclosure
    >
      <option
        value="north"
      >North terminal</option>
      <option
        value="west"
      >West terminal</option>
    </UiCombobox>
  </UiStack>;
}
/** @jsxImportSource preact */
import { UiCombobox, UiStack } from "@threadlabs/looma";

export default function Example() {
  return <UiStack
    gap="s"
  >
    <UiCombobox
      label="Readonly"
      readOnly
      value="north"
      disclosure
    >
      <option
        value="north"
      >North terminal</option>
    </UiCombobox>
    <UiCombobox
      label="Disabled"
      disabled
      disclosure
    >
      <option
        value="north"
      >North terminal</option>
    </UiCombobox>
    <UiCombobox
      label="Required"
      name="destination"
      required
      disclosure
    >
      <option
        value="north"
      >North terminal</option>
      <option
        value="west"
      >West terminal</option>
    </UiCombobox>
  </UiStack>;
}
<script>
  import { UiCombobox, UiStack } from "@threadlabs/looma";
</script>

<UiStack
  gap="s"
>
  <UiCombobox
    label="Readonly"
    readonly
    value="north"
    disclosure
  >
    <option
      value="north"
    >North terminal</option>
  </UiCombobox>
  <UiCombobox
    label="Disabled"
    disabled
    disclosure
  >
    <option
      value="north"
    >North terminal</option>
  </UiCombobox>
  <UiCombobox
    label="Required"
    name="destination"
    required
    disclosure
  >
    <option
      value="north"
    >North terminal</option>
    <option
      value="west"
    >West terminal</option>
  </UiCombobox>
</UiStack>
import { Component } from "@angular/core";
import { UiCombobox, UiStack } from "@threadlabs/looma";

@Component({
  selector: "example-view",
  standalone: true,
  imports: [UiStack, UiCombobox],
  template: `
    <div
      ui-stack
      [gap]="'s'"
    >
      <div
        ui-combobox
        [label]="'Readonly'"
        [readonly]="true"
        [value]="'north'"
        [disclosure]="true"
      >
        <option
          value="north"
        >North terminal</option>
      </div>
      <div
        ui-combobox
        [label]="'Disabled'"
        [disabled]="true"
        [disclosure]="true"
      >
        <option
          value="north"
        >North terminal</option>
      </div>
      <div
        ui-combobox
        [label]="'Required'"
        [name]="'destination'"
        [required]="true"
        [disclosure]="true"
      >
        <option
          value="north"
        >North terminal</option>
        <option
          value="west"
        >West terminal</option>
      </div>
    </div>
  `,
})
export default class Example {}

selected values

selectedValues sets the chosen options from data, here a required field with a fixed option list. The consumer owns the selection: each change the user makes is reported as selected-values-change with the new list of values, which Vue binds two-way with v-model:selected-values. A form submits one regions entry per value.

Code

<link
  rel="component"
  href="@threadlabs/looma/components/ui-combobox/ui-combobox.html"
>

<ui-combobox
  label="Regions"
  name="regions"
  multiple
  auto-highlight="single"
  select-on-tab
  required
  disclosure
  selected-values="[&quot;north&quot;,&quot;west&quot;]"
>
  <option
    value="north"
  >North</option>
  <option
    value="south"
  >South</option>
  <option
    value="east"
  >East</option>
  <option
    value="west"
  >West</option>
</ui-combobox>
<script setup lang="ts">
import { ref } from "vue";
import { UiCombobox as Combobox } from "@threadlabs/looma";

const regions = [
  { value: "north", label: "North" },
  { value: "south", label: "South" },
  { value: "east", label: "East" },
  { value: "west", label: "West" }
];
const selected = ref<readonly string[]>(["north", "west"]);
</script>

<template>
  <Combobox v-model:selected-values="selected" label="Regions" name="regions" multiple auto-highlight="single" select-on-tab required disclosure>
    <option v-for="region in regions" :key="region.value" :value="region.value">{{ region.label }}</option>
  </Combobox>
</template>
import { UiCombobox } from "@threadlabs/looma";

export default function Example() {
  return <UiCombobox
    label="Regions"
    name="regions"
    multiple
    autoHighlight="single"
    selectOnTab
    required
    disclosure
    selectedValues={["north","west"]}
  >
    <option
      value="north"
    >North</option>
    <option
      value="south"
    >South</option>
    <option
      value="east"
    >East</option>
    <option
      value="west"
    >West</option>
  </UiCombobox>;
}
/** @jsxImportSource preact */
import { UiCombobox } from "@threadlabs/looma";

export default function Example() {
  return <UiCombobox
    label="Regions"
    name="regions"
    multiple
    autoHighlight="single"
    selectOnTab
    required
    disclosure
    selectedValues={["north","west"]}
  >
    <option
      value="north"
    >North</option>
    <option
      value="south"
    >South</option>
    <option
      value="east"
    >East</option>
    <option
      value="west"
    >West</option>
  </UiCombobox>;
}
<script>
  import { UiCombobox } from "@threadlabs/looma";
</script>

<UiCombobox
  label="Regions"
  name="regions"
  multiple
  autoHighlight="single"
  selectOnTab
  required
  disclosure
  selectedValues={["north","west"]}
>
  <option
    value="north"
  >North</option>
  <option
    value="south"
  >South</option>
  <option
    value="east"
  >East</option>
  <option
    value="west"
  >West</option>
</UiCombobox>
import { Component } from "@angular/core";
import { UiCombobox } from "@threadlabs/looma";

@Component({
  selector: "example-view",
  standalone: true,
  imports: [UiCombobox],
  template: `
    <div
      ui-combobox
      [label]="'Regions'"
      [name]="'regions'"
      [multiple]="true"
      [autoHighlight]="'single'"
      [selectOnTab]="true"
      [required]="true"
      [disclosure]="true"
      [selectedValues]="['north', 'west']"
    >
      <option
        value="north"
      >North</option>
      <option
        value="south"
      >South</option>
      <option
        value="east"
      >East</option>
      <option
        value="west"
      >West</option>
    </div>
  `,
})
export default class Example {}

Browse-first suggestions

Open the list on focus and leave authored results visible while the consumer controls which options are supplied.

Code

<link
  rel="component"
  href="@threadlabs/looma/components/ui-combobox/ui-combobox.html"
>

<ui-combobox
  label="Fruit"
  open-on-focus
  filter="none"
>
  <option
    value="apple"
  >Apple</option>
  <option
    value="pear"
  >Pear</option>
  <span
    slot="empty"
  >No fruit found</span>
</ui-combobox>
<script setup>
  import { UiCombobox } from "@threadlabs/looma";
</script>

<template>
  <UiCombobox
    label="Fruit"
    :open-on-focus="true"
    filter="none"
  >
    <option
      value="apple"
    >Apple</option>
    <option
      value="pear"
    >Pear</option>
    <template #empty>
      <span>No fruit found</span>
    </template>
  </UiCombobox>
</template>
import { UiCombobox } from "@threadlabs/looma";

export default function Example() {
  return <UiCombobox
    label="Fruit"
    openOnFocus
    filter="none"
    slots={{
      empty: <span>No fruit found</span>,
    }}
  >
    <option
      value="apple"
    >Apple</option>
    <option
      value="pear"
    >Pear</option>
  </UiCombobox>;
}
/** @jsxImportSource preact */
import { UiCombobox } from "@threadlabs/looma";

export default function Example() {
  return <UiCombobox
    label="Fruit"
    openOnFocus
    filter="none"
    slots={{
      empty: <span>No fruit found</span>,
    }}
  >
    <option
      value="apple"
    >Apple</option>
    <option
      value="pear"
    >Pear</option>
  </UiCombobox>;
}
<script>
  import { UiCombobox } from "@threadlabs/looma";
</script>

{#snippet empty()}
  <span>No fruit found</span>
{/snippet}

<UiCombobox
  label="Fruit"
  openOnFocus
  filter="none"
  slots={{ empty }}
>
  <option
    value="apple"
  >Apple</option>
  <option
    value="pear"
  >Pear</option>
</UiCombobox>
import { Component } from "@angular/core";
import { UiCombobox } from "@threadlabs/looma";

@Component({
  selector: "example-view",
  standalone: true,
  imports: [UiCombobox],
  template: `
    <div
      ui-combobox
      [label]="'Fruit'"
      [openOnFocus]="true"
      [filter]="'none'"
    >
      <option
        value="apple"
      >Apple</option>
      <option
        value="pear"
      >Pear</option>
      <ng-container ngProjectAs="[slot='empty']">
        <span>No fruit found</span>
      </ng-container>
    </div>
  `,
})
export default class Example {}

Descriptions and tags

A row can carry context under its label (data-description) and a short tag after it (data-tag, with data-tag-tone for a status tone or data-tag-color for a category colour). The label stays the option's name, what filtering matches, and what the field shows once chosen; the tag and description are read as its description.

Code

<link
  rel="component"
  href="@threadlabs/looma/components/ui-combobox/ui-combobox.html"
>

<ui-combobox
  label="Directory"
  placeholder="Search people, businesses, and places…"
  disclosure
>
  <optgroup
    label="People"
  >
    <option
      value="p-riley"
      data-description="Harbor Supply Co."
      data-tag="Contact"
      data-tag-color="rebeccapurple"
    >Riley Kim</option>
    <option
      value="p-sam"
      data-description="Northwind Traders"
      data-tag="Inactive"
      data-tag-tone="warning"
    >Sam Ortiz</option>
  </optgroup>
  <optgroup
    label="Businesses"
  >
    <option
      value="b-harbor"
      data-description="Portland, OR"
      data-tag="Business"
      data-tag-color="teal"
    >Harbor Supply Co.</option>
    <option
      value="b-northwind"
      data-description="Tacoma, WA"
      data-tag="Business"
      data-tag-color="teal"
    >Northwind Traders</option>
  </optgroup>
  <optgroup
    label="Places"
  >
    <option
      value="l-dock"
      data-description="Portland, OR"
    >Dock 4 warehouse</option>
    <option
      value="l-yard"
      data-description="Tacoma, WA"
      data-tag="Closed"
      data-tag-tone="danger"
    >East yard</option>
  </optgroup>
</ui-combobox>
<script setup>
  import { UiCombobox } from "@threadlabs/looma";
</script>

<template>
  <UiCombobox
    label="Directory"
    placeholder="Search people, businesses, and places…"
    :disclosure="true"
  >
    <optgroup
      label="People"
    >
      <option
        value="p-riley"
        data-description="Harbor Supply Co."
        data-tag="Contact"
        data-tag-color="rebeccapurple"
      >Riley Kim</option>
      <option
        value="p-sam"
        data-description="Northwind Traders"
        data-tag="Inactive"
        data-tag-tone="warning"
      >Sam Ortiz</option>
    </optgroup>
    <optgroup
      label="Businesses"
    >
      <option
        value="b-harbor"
        data-description="Portland, OR"
        data-tag="Business"
        data-tag-color="teal"
      >Harbor Supply Co.</option>
      <option
        value="b-northwind"
        data-description="Tacoma, WA"
        data-tag="Business"
        data-tag-color="teal"
      >Northwind Traders</option>
    </optgroup>
    <optgroup
      label="Places"
    >
      <option
        value="l-dock"
        data-description="Portland, OR"
      >Dock 4 warehouse</option>
      <option
        value="l-yard"
        data-description="Tacoma, WA"
        data-tag="Closed"
        data-tag-tone="danger"
      >East yard</option>
    </optgroup>
  </UiCombobox>
</template>
import { UiCombobox } from "@threadlabs/looma";

export default function Example() {
  return <UiCombobox
    label="Directory"
    placeholder="Search people, businesses, and places…"
    disclosure
  >
    <optgroup
      label="People"
    >
      <option
        value="p-riley"
        data-description="Harbor Supply Co."
        data-tag="Contact"
        data-tag-color="rebeccapurple"
      >Riley Kim</option>
      <option
        value="p-sam"
        data-description="Northwind Traders"
        data-tag="Inactive"
        data-tag-tone="warning"
      >Sam Ortiz</option>
    </optgroup>
    <optgroup
      label="Businesses"
    >
      <option
        value="b-harbor"
        data-description="Portland, OR"
        data-tag="Business"
        data-tag-color="teal"
      >Harbor Supply Co.</option>
      <option
        value="b-northwind"
        data-description="Tacoma, WA"
        data-tag="Business"
        data-tag-color="teal"
      >Northwind Traders</option>
    </optgroup>
    <optgroup
      label="Places"
    >
      <option
        value="l-dock"
        data-description="Portland, OR"
      >Dock 4 warehouse</option>
      <option
        value="l-yard"
        data-description="Tacoma, WA"
        data-tag="Closed"
        data-tag-tone="danger"
      >East yard</option>
    </optgroup>
  </UiCombobox>;
}
/** @jsxImportSource preact */
import { UiCombobox } from "@threadlabs/looma";

export default function Example() {
  return <UiCombobox
    label="Directory"
    placeholder="Search people, businesses, and places…"
    disclosure
  >
    <optgroup
      label="People"
    >
      <option
        value="p-riley"
        data-description="Harbor Supply Co."
        data-tag="Contact"
        data-tag-color="rebeccapurple"
      >Riley Kim</option>
      <option
        value="p-sam"
        data-description="Northwind Traders"
        data-tag="Inactive"
        data-tag-tone="warning"
      >Sam Ortiz</option>
    </optgroup>
    <optgroup
      label="Businesses"
    >
      <option
        value="b-harbor"
        data-description="Portland, OR"
        data-tag="Business"
        data-tag-color="teal"
      >Harbor Supply Co.</option>
      <option
        value="b-northwind"
        data-description="Tacoma, WA"
        data-tag="Business"
        data-tag-color="teal"
      >Northwind Traders</option>
    </optgroup>
    <optgroup
      label="Places"
    >
      <option
        value="l-dock"
        data-description="Portland, OR"
      >Dock 4 warehouse</option>
      <option
        value="l-yard"
        data-description="Tacoma, WA"
        data-tag="Closed"
        data-tag-tone="danger"
      >East yard</option>
    </optgroup>
  </UiCombobox>;
}
<script>
  import { UiCombobox } from "@threadlabs/looma";
</script>

<UiCombobox
  label="Directory"
  placeholder="Search people, businesses, and places…"
  disclosure
>
  <optgroup
    label="People"
  >
    <option
      value="p-riley"
      data-description="Harbor Supply Co."
      data-tag="Contact"
      data-tag-color="rebeccapurple"
    >Riley Kim</option>
    <option
      value="p-sam"
      data-description="Northwind Traders"
      data-tag="Inactive"
      data-tag-tone="warning"
    >Sam Ortiz</option>
  </optgroup>
  <optgroup
    label="Businesses"
  >
    <option
      value="b-harbor"
      data-description="Portland, OR"
      data-tag="Business"
      data-tag-color="teal"
    >Harbor Supply Co.</option>
    <option
      value="b-northwind"
      data-description="Tacoma, WA"
      data-tag="Business"
      data-tag-color="teal"
    >Northwind Traders</option>
  </optgroup>
  <optgroup
    label="Places"
  >
    <option
      value="l-dock"
      data-description="Portland, OR"
    >Dock 4 warehouse</option>
    <option
      value="l-yard"
      data-description="Tacoma, WA"
      data-tag="Closed"
      data-tag-tone="danger"
    >East yard</option>
  </optgroup>
</UiCombobox>
import { Component } from "@angular/core";
import { UiCombobox } from "@threadlabs/looma";

@Component({
  selector: "example-view",
  standalone: true,
  imports: [UiCombobox],
  template: `
    <div
      ui-combobox
      [label]="'Directory'"
      [placeholder]="'Search people, businesses, and places…'"
      [disclosure]="true"
    >
      <optgroup
        label="People"
      >
        <option
          value="p-riley"
          data-description="Harbor Supply Co."
          data-tag="Contact"
          data-tag-color="rebeccapurple"
        >Riley Kim</option>
        <option
          value="p-sam"
          data-description="Northwind Traders"
          data-tag="Inactive"
          data-tag-tone="warning"
        >Sam Ortiz</option>
      </optgroup>
      <optgroup
        label="Businesses"
      >
        <option
          value="b-harbor"
          data-description="Portland, OR"
          data-tag="Business"
          data-tag-color="teal"
        >Harbor Supply Co.</option>
        <option
          value="b-northwind"
          data-description="Tacoma, WA"
          data-tag="Business"
          data-tag-color="teal"
        >Northwind Traders</option>
      </optgroup>
      <optgroup
        label="Places"
      >
        <option
          value="l-dock"
          data-description="Portland, OR"
        >Dock 4 warehouse</option>
        <option
          value="l-yard"
          data-description="Tacoma, WA"
          data-tag="Closed"
          data-tag-tone="danger"
        >East yard</option>
      </optgroup>
    </div>
  `,
})
export default class Example {}

Discard unfinished search

Browse a small authored list on focus; leaving the multiple combobox clears unfinished text and keeps chosen items.

Code

<link
  rel="component"
  href="@threadlabs/looma/components/ui-combobox/ui-combobox.html"
>

<ui-combobox
  label="Teams"
  multiple
  clear-query-on-blur
  open-on-focus
  disclosure
>
  <option
    value="design"
  >Design</option>
  <option
    value="docs"
  >Docs</option>
  <option
    value="platform"
  >Platform</option>
</ui-combobox>
<script setup>
  import { UiCombobox } from "@threadlabs/looma";
</script>

<template>
  <UiCombobox
    label="Teams"
    :multiple="true"
    :clear-query-on-blur="true"
    :open-on-focus="true"
    :disclosure="true"
  >
    <option
      value="design"
    >Design</option>
    <option
      value="docs"
    >Docs</option>
    <option
      value="platform"
    >Platform</option>
  </UiCombobox>
</template>
import { UiCombobox } from "@threadlabs/looma";

export default function Example() {
  return <UiCombobox
    label="Teams"
    multiple
    clearQueryOnBlur
    openOnFocus
    disclosure
  >
    <option
      value="design"
    >Design</option>
    <option
      value="docs"
    >Docs</option>
    <option
      value="platform"
    >Platform</option>
  </UiCombobox>;
}
/** @jsxImportSource preact */
import { UiCombobox } from "@threadlabs/looma";

export default function Example() {
  return <UiCombobox
    label="Teams"
    multiple
    clearQueryOnBlur
    openOnFocus
    disclosure
  >
    <option
      value="design"
    >Design</option>
    <option
      value="docs"
    >Docs</option>
    <option
      value="platform"
    >Platform</option>
  </UiCombobox>;
}
<script>
  import { UiCombobox } from "@threadlabs/looma";
</script>

<UiCombobox
  label="Teams"
  multiple
  clearQueryOnBlur
  openOnFocus
  disclosure
>
  <option
    value="design"
  >Design</option>
  <option
    value="docs"
  >Docs</option>
  <option
    value="platform"
  >Platform</option>
</UiCombobox>
import { Component } from "@angular/core";
import { UiCombobox } from "@threadlabs/looma";

@Component({
  selector: "example-view",
  standalone: true,
  imports: [UiCombobox],
  template: `
    <div
      ui-combobox
      [label]="'Teams'"
      [multiple]="true"
      [clearQueryOnBlur]="true"
      [openOnFocus]="true"
      [disclosure]="true"
    >
      <option
        value="design"
      >Design</option>
      <option
        value="docs"
      >Docs</option>
      <option
        value="platform"
      >Platform</option>
    </div>
  `,
})
export default class Example {}

Wrap selected items before scrolling

grow with maxRows lets a multiple field grow through three rows before additional selections scroll vertically inside the field. The input remains reachable by keyboard.

Code

<link
  rel="component"
  href="@threadlabs/looma/components/ui-container/ui-container.html"
>
<link
  rel="component"
  href="@threadlabs/looma/components/ui-combobox/ui-combobox.html"
>

<ui-container
  fill
>
  <ui-combobox
    label="Topics"
    multiple
    grow
    max-rows="3"
    disclosure
    placeholder="Add a topic…"
  >
    <option
      value="research"
      selected
    >Research and discovery</option>
    <option
      value="design"
      selected
    >Interface design</option>
    <option
      value="content"
      selected
    >Content strategy</option>
    <option
      value="accessibility"
      selected
    >Accessibility review</option>
    <option
      value="delivery"
    >Delivery</option>
  </ui-combobox>
</ui-container>
<script setup>
  import { UiCombobox, UiContainer } from "@threadlabs/looma";
</script>

<template>
  <UiContainer
    :fill="true"
  >
    <UiCombobox
      label="Topics"
      :multiple="true"
      :grow="true"
      :max-rows="3"
      :disclosure="true"
      placeholder="Add a topic…"
    >
      <option
        value="research"
        selected
      >Research and discovery</option>
      <option
        value="design"
        selected
      >Interface design</option>
      <option
        value="content"
        selected
      >Content strategy</option>
      <option
        value="accessibility"
        selected
      >Accessibility review</option>
      <option
        value="delivery"
      >Delivery</option>
    </UiCombobox>
  </UiContainer>
</template>
import { UiCombobox, UiContainer } from "@threadlabs/looma";

export default function Example() {
  return <UiContainer
    fill
  >
    <UiCombobox
      label="Topics"
      multiple
      grow
      maxRows={3}
      disclosure
      placeholder="Add a topic…"
    >
      <option
        value="research"
        selected
      >Research and discovery</option>
      <option
        value="design"
        selected
      >Interface design</option>
      <option
        value="content"
        selected
      >Content strategy</option>
      <option
        value="accessibility"
        selected
      >Accessibility review</option>
      <option
        value="delivery"
      >Delivery</option>
    </UiCombobox>
  </UiContainer>;
}
/** @jsxImportSource preact */
import { UiCombobox, UiContainer } from "@threadlabs/looma";

export default function Example() {
  return <UiContainer
    fill
  >
    <UiCombobox
      label="Topics"
      multiple
      grow
      maxRows={3}
      disclosure
      placeholder="Add a topic…"
    >
      <option
        value="research"
        selected
      >Research and discovery</option>
      <option
        value="design"
        selected
      >Interface design</option>
      <option
        value="content"
        selected
      >Content strategy</option>
      <option
        value="accessibility"
        selected
      >Accessibility review</option>
      <option
        value="delivery"
      >Delivery</option>
    </UiCombobox>
  </UiContainer>;
}
<script>
  import { UiCombobox, UiContainer } from "@threadlabs/looma";
</script>

<UiContainer
  fill
>
  <UiCombobox
    label="Topics"
    multiple
    grow
    maxRows={3}
    disclosure
    placeholder="Add a topic…"
  >
    <option
      value="research"
      selected
    >Research and discovery</option>
    <option
      value="design"
      selected
    >Interface design</option>
    <option
      value="content"
      selected
    >Content strategy</option>
    <option
      value="accessibility"
      selected
    >Accessibility review</option>
    <option
      value="delivery"
    >Delivery</option>
  </UiCombobox>
</UiContainer>
import { Component } from "@angular/core";
import { UiCombobox, UiContainer } from "@threadlabs/looma";

@Component({
  selector: "example-view",
  standalone: true,
  imports: [UiContainer, UiCombobox],
  template: `
    <div
      ui-container
      [fill]="true"
    >
      <div
        ui-combobox
        [label]="'Topics'"
        [multiple]="true"
        [grow]="true"
        [maxRows]="3"
        [disclosure]="true"
        [placeholder]="'Add a topic…'"
      >
        <option
          value="research"
          selected
        >Research and discovery</option>
        <option
          value="design"
          selected
        >Interface design</option>
        <option
          value="content"
          selected
        >Content strategy</option>
        <option
          value="accessibility"
          selected
        >Accessibility review</option>
        <option
          value="delivery"
        >Delivery</option>
      </div>
    </div>
  `,
})
export default class Example {}

API

Package: @threadlabs/looma · Native root: div

Attributes

NameDescriptionPropertyTypeDefaultAllowed values
allow-createOffers the current query as a new option, reported as create-item. When nothing else matches, the offer is highlighted, so Enter creates it; with nothing highlighted, Enter in multiple mode commits the typed text as a token separator does.allowCreatebooleanfalse—
allow-free-textAllows values that do not match an authored option.allowFreeTextbooleanfalse—
auto-highlightsingle highlights the only enabled authored suggestion while typing. Ambiguous results and an empty query stay unhighlighted. none preserves manual highlighting with the arrow keys.autoHighlightkeywordnonenone, single
clear-query-on-blurIn multiple mode, clears unfinished search text when focus leaves the whole combobox, preserving selected items. A controlled query reports query-change with an empty query; the consumer must reflect it back. Does not choose or create an option. The default preserves unfinished text. Single mode keeps its existing selection and free-text resolution.clearQueryOnBlurbooleanfalse—
clearableAdds a clear button to the field that empties the input and clears the selection, reported as value-change with kind "clear". It is disabled when there is nothing to clear. In multiple mode it clears only the typed text; chosen items stay.clearablebooleanfalse—
disabledDisables the input and every button in the field: the chosen-item badges, the clear and disclosure buttons, and the help button. The list closes and cannot be opened, the value cannot be cleared, and a named combobox submits nothing with its form.disabledbooleanfalse—
disclosureAdds a chevron button that opens and closes the full, unfiltered list of options, for users who would rather browse than type. ArrowDown opens the same list with or without it.disclosurebooleanfalse—
filterHow the list narrows as the user types. label lists the options whose label contains the typed text, ignoring case. none lists every authored option, for options already narrowed elsewhere, such as a server search, so a result that matched on data other than its label still shows. Leaving the field still commits an option whose label matches the text, or the only one listed.filterkeywordlabellabel, none
growLet a multiple-selection field wrap and grow with its selected items and typing space. Without grow it stays one horizontally scrolling row.growbooleanfalse—
helpHelp text for the field. When set, a help button appears beside the field and opens a tooltip with this text; while it is open, the input is described by it.helpstring—
invalidExposes an externally validated error on the input and field. It remains until the consumer clears it, independently of native validation.invalidbooleanfalse—
itemsThe selected items in multiple mode, as JSON; a named combobox submits each one's value. A form reset returns to these items, or to authored selected options when unset.itemslist(object)
  • [].id: string (required)
  • [].value: string (required)
  • [].label: string (required)
  • [].group: string
  • [].disabled: boolean
  • [].description: string
  • [].tag: object
  • [].tag.label: string (required)
  • [].tag.tone: keyword
  • [].tag.color: string
——
labelThe field's label, tied to its input and shown above it; required adds an asterisk. It also names the suggestion list. Pair it with labelVisibility="sr-only" when the context already labels the field visibly.labelstring—
label-visibilityvisible shows the label above the field; sr-only hides it visually but keeps it as the input's accessible name. Use sr-only only when the surrounding layout already makes the field's purpose clear.labelVisibilitykeywordvisiblevisible, sr-only
loadingMarks the suggestion list busy while the consumer loads options. It announces loading and suppresses the empty state and create offer until cleared.loadingbooleanfalse—
max-rowsOptional maximum visible rows when grow is enabled. Extra selections scroll vertically inside the field. Omit it for unbounded growth; single-selection fields are unchanged.maxRowsinteger——
multipleLets the user choose several options. Each choice becomes a removable badge before the input, the list stays open between picks, and choosing a checked option removes it. items-change then reports the whole list of items, and selected-values-change the list of their values; use selectedValues or items, not value, in this mode.multiplebooleanfalse—
mutedShows the selected field value with supporting-text emphasis, for an inherited or default choice. Suggestions keep normal emphasis and the field stays interactive.mutedbooleanfalse—
nameThe form field name the combobox submits its value under, never the label shown in the field. Single mode sends one entry: the selected option's value, the typed text when allowFreeText is set and no option is selected, or an empty string. Multiple mode sends one entry per chosen item's value, and nothing when none is chosen. A disabled combobox sends nothing.namestring—
open-on-focusOpens suggestions when the input receives focus or is clicked. A committed selection shows all choices until typing filters them; an explicitly supplied query keeps its filtering.openOnFocusbooleanfalse—
placeholderHint text shown in the empty input, as on a native input. It disappears as the user types, so it never replaces label.placeholderstring—
queryThe input's text, when the consumer controls it. Once set, the consumer owns the text: typing reports query-change, and the input returns to query unless query is updated to match. Leave it unset to let the combobox manage its own text, showing the chosen option's label.querystring——
readonlyShows the current value without letting it change: the text can be selected but not edited, the list does not open, and the clear, disclosure, and badge remove buttons are disabled. A named combobox still submits its value.readonlybooleanfalse—
requiredRequires a value: adds an asterisk to the label, marks the input required for native form validation, and makes validation report "A value is required." when the field is left empty. In multiple mode a chosen item satisfies it, whatever is left in the input.requiredbooleanfalse—
select-on-tabCommits a highlighted authored suggestion on forward Tab, then lets focus advance normally. In multiple mode a selected suggestion is retained without duplication or removal. Shift+Tab does not commit, and Tab never chooses the create offer.selectOnTabbooleanfalse—
selected-valuesThe selected option values in multiple mode, when the consumer controls the selection. Without it or items, authored options with selected set the initial selection. Once set, the consumer owns it: each value shows as a badge with its authored option's label, adding or removing one reports selected-values-change with the new list, and the badges follow selectedValues, not the user, unless it is updated to match. Setting it reports nothing. It takes precedence over items; leave it unset to let the combobox keep its own selection.selectedValueslist(string)——
sizeField height, padding, and type size, matching Button's sizes so a field and a button of one size share a row. sm is the small control height (2rem by default) with smaller text, for compact rows such as a table row or a filter bar; md is the standard control height; lg is taller with roomier padding. Touch input keeps body-size field text without inflating the visible size ladder. The label keeps its size.sizekeywordmdsm, md, lg
token-separatorsKeys that commit the typed text in multiple mode, as KeyboardEvent key values such as "," or ";". The text is added as the option whose label matches it, ignoring case, or with allowCreate is reported as create-item; otherwise it stays in the input.tokenSeparatorslist(string)——
valueThe selected value in single mode, which a named combobox submits with its form. The field shows the matching option's label, and a form reset returns to this value. In a strict combobox, typing a search does not change the selection; leaving with no match restores its label. If omitted, the first authored option with selected sets the initial value.valuestring——

Framework props

NameTypeDefaultAllowed values
allowCreatebooleanfalse—
allowFreeTextbooleanfalse—
autoHighlight"none" | "single"nonenone, single
clearablebooleanfalse—
clearQueryOnBlurbooleanfalse—
disabledbooleanfalse—
disclosurebooleanfalse—
filter"label" | "none"labellabel, none
growbooleanfalse—
helpstring—
invalidbooleanfalse—
itemsreadonly ({ readonly id: string; readonly value: string; readonly label: string; readonly group?: string | null; readonly disabled?: boolean | null; readonly description?: string | null; readonly tag?: { readonly label: string; readonly tone?: "neutral" | "accent" | "info" | "success" | "warning" | "danger" | null; readonly color?: string | null } | null })[]
  • [].id: string (required)
  • [].value: string (required)
  • [].label: string (required)
  • [].group: string
  • [].disabled: boolean
  • [].description: string
  • [].tag: object
  • [].tag.label: string (required)
  • [].tag.tone: keyword
  • [].tag.color: string
——
labelstring—
labelVisibility"visible" | "sr-only"visiblevisible, sr-only
loadingbooleanfalse—
maxRowsnumber——
multiplebooleanfalse—
mutedbooleanfalse—
namestring—
openOnFocusbooleanfalse—
placeholderstring—
querystring——
readonlybooleanfalse—
requiredbooleanfalse—
selectedValuesreadonly (string)[]——
selectOnTabbooleanfalse—
size"sm" | "md" | "lg"mdsm, md, lg
tokenSeparatorsreadonly (string)[]——
valuestring——

Events

NameDetailDescription
add-itemobject
  • item: object (required)
  • item.id: string (required)
  • item.value: string (required)
  • item.label: string (required)
  • item.group: string
  • item.disabled: boolean
  • item.description: string
  • item.tag: object
  • item.tag.label: string (required)
  • item.tag.tone: keyword
  • item.tag.color: string
  • index: integer (required)
  • trigger: keyword (required)
Emitted with the declared detail payload.
create-entryobject
  • value: string
  • query: string (required)
  • option: object
  • option.id: string (required)
  • option.value: string (required)
  • option.label: string (required)
  • option.group: string
  • option.disabled: boolean
  • option.description: string
  • option.tag: object
  • option.tag.label: string (required)
  • option.tag.tone: keyword
  • option.tag.color: string
  • kind: keyword (required)
  • trigger: keyword (required)
Emitted with the declared detail payload.
create-itemobject
  • query: string (required)
  • trigger: keyword (required)
Emitted with the declared detail payload.
free-entryobject
  • value: string
  • query: string (required)
  • option: object
  • option.id: string (required)
  • option.value: string (required)
  • option.label: string (required)
  • option.group: string
  • option.disabled: boolean
  • option.description: string
  • option.tag: object
  • option.tag.label: string (required)
  • option.tag.tone: keyword
  • option.tag.color: string
  • kind: keyword (required)
  • trigger: keyword (required)
Emitted with the declared detail payload.
items-changelist(object)
  • [].id: string (required)
  • [].value: string (required)
  • [].label: string (required)
  • [].group: string
  • [].disabled: boolean
  • [].description: string
  • [].tag: object
  • [].tag.label: string (required)
  • [].tag.tone: keyword
  • [].tag.color: string
Emitted with the declared detail payload.
options-changelist(object)
  • [].id: string (required)
  • [].value: string (required)
  • [].label: string (required)
  • [].group: string
  • [].disabled: boolean
  • [].description: string
  • [].tag: object
  • [].tag.label: string (required)
  • [].tag.tone: keyword
  • [].tag.color: string
Emitted with the declared detail payload.
query-changeobject
  • query: string (required)
  • display: string (required)
  • trigger: keyword (required)
Emitted with the declared detail payload.
remove-itemobject
  • item: object (required)
  • item.id: string (required)
  • item.value: string (required)
  • item.label: string (required)
  • item.group: string
  • item.disabled: boolean
  • item.description: string
  • item.tag: object
  • item.tag.label: string (required)
  • item.tag.tone: keyword
  • item.tag.color: string
  • index: integer (required)
  • trigger: keyword (required)
Emitted with the declared detail payload.
selected-values-changeobject
  • selectedValues: list(string) (required)
  • trigger: keyword (required)
Emitted with the declared detail payload.
validation-changeobject
  • status: keyword (required)
  • touched: boolean (required)
  • dirty: boolean (required)
  • issues: list(object) (required)
  • issues[].message: string (required)
  • issues[].path: list(unknown)
  • issues[].severity: keyword
  • output: unknown
Emitted with the declared detail payload.
value-changeobject
  • value: string
  • query: string (required)
  • option: object
  • option.id: string (required)
  • option.value: string (required)
  • option.label: string (required)
  • option.group: string
  • option.disabled: boolean
  • option.description: string
  • option.tag: object
  • option.tag.label: string (required)
  • option.tag.tone: keyword
  • option.tag.color: string
  • kind: keyword (required)
  • trigger: keyword (required)
Emitted with the declared detail payload.

Slots

NamePurpose
itemNamed content for the item region.
optionNamed content for the option region.
startNamed content for the start region.
emptyNamed content for the empty region.
footerNamed content for the footer region.
defaultDefault child content.

Design tokens

Set shared theme properties on a theme boundary. Component hooks apply only to their owning component.

Component tokens

TokenDeclared valuesFallback
--ui-combobox-affordance-text—var(--ui-text-secondary)
--ui-combobox-invalid-border—var(--ui-field-danger, var(--ui-danger-solid, var(--ui-accent-active)))
--ui-combobox-item-input-min-inline-size—5rem
--ui-combobox-item-item-max-inline-size—12rem
--ui-combobox-item-min-block-sizevar(--ui-control-size-md) | var(--ui-control-size-sm) | var(--ui-control-size-lg)—
--ui-combobox-label-font-size—var(--ui-field-label-font-size, var(--ui-font-size-md))
--ui-combobox-label-text—var(--ui-text-primary)
--ui-combobox-max-block-size—18rem
--ui-combobox-message-text—var(--ui-text-secondary)
--ui-combobox-option-check——
--ui-combobox-option-text—inherit
--ui-combobox-popup-border—var(--ui-overlay-border, var(--ui-border-strong))
--ui-combobox-popup-radius—var(--ui-overlay-radius, var(--ui-radius-md))
--ui-combobox-popup-shadow—var(--ui-overlay-shadow, var(--ui-elevation-overlay, var(--ui-shadow-lg)))
--ui-combobox-popup-surface—var(--ui-material-content, var(--ui-surface-elevated))
--ui-combobox-radius—var(--ui-field-radius, var(--ui-radius-md))

Shared tokens

TokenFallback
--ui-accent-active—
--ui-accent-solid—
--ui-border-default—
--ui-border-strong—
--ui-border-width—
--ui-control-bordervar(--ui-border-default)
--ui-control-focusvar(--ui-accent-solid)
--ui-control-focus-halo-shadow—
--ui-control-inset—
--ui-control-inset-block-lgvar(--ui-space-3)
--ui-control-inset-block-mdvar(--ui-space-2)
--ui-control-inset-block-smvar(--ui-space-1)
--ui-control-size-lg—
--ui-control-size-md—
--ui-control-size-sm—
--ui-control-surfacevar(--ui-surface-default)
--ui-control-surface-disabledvar(--ui-surface-muted)
--ui-danger-solidvar(--ui-accent-active)
--ui-disabled-text—
--ui-elevation-overlayvar(--ui-shadow-lg)
--ui-field-dangervar(--ui-danger-solid, var(--ui-accent-active))
--ui-field-label-font-sizevar(--ui-font-size-md)
--ui-field-radiusvar(--ui-radius-md)
--ui-focus-halo—
--ui-focus-ring—
--ui-focus-width—
--ui-font-size-md—
--ui-font-size-sm—
--ui-icon-size-sm—
--ui-line-height-md—
--ui-line-height-tight—
--ui-material-contentvar(--ui-surface-elevated)
--ui-motion-ease—
--ui-motion-fast—
--ui-overlay-bordervar(--ui-border-strong)
--ui-overlay-radiusvar(--ui-radius-md)
--ui-overlay-shadowvar(--ui-elevation-overlay, var(--ui-shadow-lg))
--ui-radius-md—
--ui-radius-round—
--ui-radius-sm—
--ui-shadow-lg—
--ui-space-0-5—
--ui-space-1—
--ui-space-2—
--ui-space-3—
--ui-space-4—
--ui-surface-default—
--ui-surface-elevated—
--ui-surface-muted—
--ui-text-muted—
--ui-text-primary—
--ui-text-secondary—