Select

Select lets users choose one option or several from a searchable list.

import Select from '@/components/ui/select';

const frameworks = [
  { value: 'next', label: 'Next.js' },

Installation

Add this component with the NateUI CLI.

npx @nateui/cli@latest add Select

Examples

Basic

import Select from '@/components/ui/select';

const roles = [
  { value: 'owner', label: 'Owner' },

Multiple

import Select from '@/components/ui/select';

const skills = [
  { value: 'ts', label: 'TypeScript' },

Size

import Select from '@/components/ui/select';

const timezones = [
  { value: 'utc', label: 'UTC' },

Searchable

import Select from '@/components/ui/select';

const countries = [
  { value: 'us', label: 'United States' },

Disabled

import Select from '@/components/ui/select';

const plans = [
  { value: 'free', label: 'Free' },

Grouped

import Select from '@/components/ui/select';

const groupedOptions = [
  {

Custom Options

import Select from '@/components/ui/select';
import Avatar from '@/components/ui/avatar';

const members = [

Creatable

import { useState } from 'react';
import Select from '@/components/ui/select';

type Tag = { value: string; label: string };

Async

import { useState } from 'react';
import Select from '@/components/ui/select';

type Repo = { value: string; label: string };

Controlled

import { useState } from 'react';
import Select from '@/components/ui/select';

type Option = { value: string; label: string };

API

Select ships two controls from one import: Select for a single choice and Select.Multi for several. Both take the same options shape — a flat array of { label, value } items, or an array of { label, options } groups — and share the search, loading, sizing, and validation props. Select.ValueWithPrefix and Select.OptionWithPrefix are helpers for the custom render props.

Select

PropDescriptionTypeDefault
optionsSelectable options: a flat list, or groups of options.Options<T>[]
valueSelected option in controlled mode.SingleOption<T> | null-
defaultValueInitial selected option when uncontrolled.SingleOption<T> | null-
onChangeFires with the newly selected option.(value: SingleOption<T>) => void-
placeholderText shown when nothing is selected.string-
isSearchableShow a filter input inside the menu.booleanfalse
isCreatableLet the filter text become a new option.booleanfalse
isDisabledDisable the whole control.booleanfalse
isLoadingShow a spinner in the control.booleanfalse
invalidApply the invalid style; also inherited from an invalid Form.Field.booleanfalse
sizeControl size; falls back to InputGroup, Form, then ConfigProvider.ControlSize'md'
placementMenu placement relative to the control.Placement-
customInputDisplayRender the selected value in the control yourself.(selectedItem: SingleOption<T> | null) => ReactNode-
customOptionRender each option row yourself.CustomOption<T>-
formatGroupLabelRender a group's header label.(group: GroupOption<T>) => ReactNode-
filterReplace the default option filtering.FilterFunction<T>-
noOptionsMessageMessage shown when no options match.string | ((ListElement) => ReactNode)'No options'
onInputChangeFires with the filter text as the user types.(inputValue: string) => void-
onMenuOpenFires when the menu opens.() => void-
searchInputPropsExtra props for the filter input.Omit<ComponentProps<'input'>, 'onChange' | 'value' | 'onKeyDown' | 'ref'>-
inputIdid for the underlying input, for label association.string-
classNameClass names for the control element.string-
...nativePropsNative div props (except defaultValue and onChange).Omit<ComponentPropsWithRef<'div'>, 'defaultValue' | 'onChange'>-

Select.Multi

Select.Multi shares every Select prop above except customInputDisplay, and replaces the single-value props with array equivalents.

PropDescriptionTypeDefault
valueSelected options in controlled mode.SelectedOptions<T>-
defaultValueInitial selected options when uncontrolled.SelectedOptions<T>-
onChangeFires with the full array of selected options.(value: SelectedOptions<T>) => void-
customLabelRender each selected tag's content yourself.(selectedItem: SingleOption<T>) => ReactNode-
showClearAllButtonShow the per-tag remove buttons and the clear-all control.booleantrue
filterReplace the default option filtering.FilterFunctionMulti<T>-

Select.ValueWithPrefix

PropDescriptionTypeDefault
labelThe value's main content.ReactNode-
prefixNode rendered before the label, such as an avatar or icon.ReactNode-
showPrefixWhether to render the prefix.booleantrue

Select.OptionWithPrefix

PropDescriptionTypeDefault
labelThe option's main content.ReactNode-
prefixNode rendered before the label, such as an avatar or icon.ReactNode-
selectedWhether this option is currently selected.booleanfalse
checkIconNode shown on the right when selected; pass the CheckIcon from customOption.ReactNode-

Types

type ControlSize = 'sm' | 'md' | 'lg'
 
// A single option. Extra keys of T (e.g. an avatar or color) are kept
// on the option and passed back to the custom render props.
type SingleOption<T> = {
  label: string
  value: any
  disabled?: boolean
} & T
 
// A labelled group of single options.
type GroupOption<T> = {
  label: string
  options: SingleOption<T>[]
}
 
// options accepts a flat list or a list of groups.
type Options<T> = SingleOption<T>[] | GroupOption<T>[]
 
// Select.Multi value / defaultValue.
type SelectedOptions<T> = SingleOption<T>[]
 
type CustomOption<T> = (props: {
  option: SingleOption<T>
  hovered: boolean
  selected: boolean
  CheckIcon: ReactNode
}) => ReactNode
 
type FilterFunction<T> = (props: {
  inputValue: string
  options: Options<T>
  selectedItem?: SingleOption<T> | null
}) => Options<T>
 
type FilterFunctionMulti<T> = (props: {
  inputValue: string
  options: Options<T>
  selectedItems: SingleOption<T>[]
}) => Options<T>
 
// Placement is re-exported from @floating-ui/react:
// 'top' | 'top-start' | 'top-end' | 'bottom' | 'bottom-start'
//   | 'bottom-end' | 'left' | 'left-start' | 'left-end'
//   | 'right' | 'right-start' | 'right-end'