Free
Pro

Select

Base UI (Angular) select is a custom listbox, not a styled native select. Install custom-select with the CLI, bind ngModel, formControlName, or Angular 22 [formField], and project ng-template baseSelectOption when a row needs more than a label.

When to use

  • Single choice from a known list with custom option layout.
  • Forms that already use Base UI (Angular) input-group error and disabled patterns, including signal forms.

When not to use

  • Typeahead or async search — use combobox.
  • Many options with checkboxes — use multi-select (Pro).

Install with npx base-ui-cli add custom-select.

freeSignal Forms

Playground

Playground

HTML

<base-custom-select
  [options]="cars"
  displayKey="label"
  valueKey="value"
  [(ngModel)]="selectedCar"
  placeholder="Choose a car…">
</base-custom-select>

Default Select

Use <option> tag inside <base-select> component and you'll get the expected result. As usual the first element works as a placeholder. See example before

Select with Placeholder

You can use the placeholder attribute to show a descriptive text when no option is selected.

Select Disabled

Use [disabled]="true" inside <base-select> tag to disable that select.

Custom Select

The <base-custom-select> is a non-native styling component that provides more control over the appearance.

Select your favorite car
Selected value: None

Option template

Project ng-template baseSelectOption to customize listbox rows. Import CustomSelectOptionDirective. Context: let-option, let-label="label", let-selected="selected".

Select your favorite car

Sizes

Use the size property to change the height of the select component. Available sizes match our standard inputs: 'sm' | 'default' | 'xl'.

Empty, error, disabled

Disabled is a native attribute. Empty options still show the trigger. Keep validation copy next to the control — do not nest base-custom-select in base-input-group.

Select a car to continue.

Forms

base-custom-select is a CVA control. Bind Angular 22 [formField] or formControlName / [(ngModel)] on the host — not inside an input-group.

Favorite car

Selected: bmw

HTML

<base-custom-select
  [options]="cars"
  displayKey="label"
  valueKey="value"
  [formField]="carForm.car">
</base-custom-select>

Native inputs take [formField] directly. CVA hosts (base-toggle, base-custom-select, combobox) use the same binding via Angular’s CVA interop. Full recipe: signal forms cookbook.

Keyboard & accessibility

Role
Native base-select is a select. base-custom-select is a combobox with a listbox.
Focus
Focus stays on the trigger. Arrow keys move the active option; Enter commits.

Shortcuts

  • TabFocus the trigger
  • EnterOpen or select the highlighted option
  • ArrowUpMove highlight up
  • ArrowDownMove highlight down
  • EscClose the list

Site-wide VPAT-style notes live on the accessibility report.

Unit tests: copy CustomSelectHarness with custom-select and load it with TestbedHarnessEnvironment.loader(fixture). See Getting started — Testing.

Installation

Run the following command to add this component to your project:

bash

npx base-ui-cli add custom-select
npx base-ui-cli add select

API Reference

For AI agents

Copy a prompt with the registry name, CLI install, and import — or add the Base UI MCP server.

bash

npx -y base-ui-ng-mcp

Base UI provides standalone components. Import the exact elements you want to use into your component.

typescript (Example)

// Install: npx base-ui-cli add custom-select
// Paths are relative to aliases.components (default: src/app/components)
import { CustomSelectOptionContext, CustomSelectOptionDirective } from './custom-select/custom-select-option.directive';
import { CustomSelectComponent } from './custom-select/custom-select.component';

@Component({
  selector: 'app-your-component',
  imports: [
    CustomSelectComponent,
    CustomSelectOptionDirective
  ],
  template: `...`
})
export class YourComponent {}

API for custom-select — generated from JSDoc in the library source.

API reference for custom-select
APIMemberTypeDefaultDescription
CustomSelectOptionContext$implicitunknown
CustomSelectOptionContextoptionunknown
CustomSelectOptionContextlabelunknown
CustomSelectOptionContextselectedboolean
CustomSelectOptionContextactiveboolean
CustomSelectOptionContextindexnumber
base-custom-selectclassstring''Additional host CSS classes (merged via cn()).
base-custom-selectlabelstring''
base-custom-selectplaceholderunknown'Select an option'
base-custom-selectoptionsunknown[][]
base-custom-selectdisplayKeyunknown'label'
base-custom-selectvalueKeyunknown'value'
base-custom-selectmultiplebooleanfalse
base-custom-select(selectionChange)voidEmits when selectionChange occurs.
[baseSelectOption]Marks an `ng-template` as the option renderer for . When omitted, the listbox shows `displayKey` (or the option itself).