Select

Select

A dropdown menu for selecting a single option from a list, with support for search, custom styling, and controlled/uncontrolled usage.


Import

tsx
import { Select } from "asheeui";

Usage

tsx
"use client";
import { useState } from "react";
import { Select } from "asheeui";
const options = [
{ label: "Option 1", value: "1" },
{ label: "Option 2", value: "2" },
{ label: "Option 3", value: "3" },
];
export default function SelectBasic() {
const [value, setValue] = useState<string | number>("");
return (
<div className="w-full max-w-md">
<Select
value={value}
onValueChange={setValue}
options={options}
placeholder="Choose an option..."
/>
</div>
);
}

Examples

Controlled

Selected: react

With default value

With below list content


Inheritance

Select shares common foundational props with <Input />, including:

  • size, radius, variant, color
  • label, labelAlign, description, message
  • status, required, isLoading, disabled
  • className, and all native field attributes

Reference: For a complete list of inherited props with detailed descriptions, see the Input documentation.

What Select adds

Select extends Input with the following additional features:

FeatureDescription
Options ListA dropdown menu showing selectable options
Single SelectionSelection handling with onValueChange callback
Search FilteringOptional real-time search to filter options
Below List ContentAbility to render custom content below the options list
Menu ConfigurationFull control over dropdown menu appearance and behavior

What Select modifies

ModificationDescription
TriggerUses a Button component instead of an input field
startContentAvailable as a prop for the trigger button
endContentAvailable as a prop for the trigger button
onChangeNative select change event with synthetic event
valueControlled selected value for single selection

What Select does not inherit

The following Input props are not available on Select:

PropReason
typeNot applicable - Select uses a button trigger
placeholderReplaced with placeholder for the trigger button
autoCompleteNot applicable
inputModeNot applicable
patternNot applicable

All other Input props are fully supported. See the Input documentation for the complete list.


Props

PropTypeDefaultDescription
optionsSelectMenuOption[]NoneList of selectable options (required)
valuestring | numberNoneControlled selected value
onValueChange(value: string | number) => voidNoneCallback when selection changes
onChange(e: React.ChangeEvent<HTMLSelectElement>) => voidNoneNative select change event callback
initialValuestring | numberNoneDefault value for uncontrolled usage
placeholderstring"Select..."Placeholder text when no selection
isSearchbooleanfalseEnable search in dropdown
searchPlaceholderstring"Search options..."Search input placeholder
searchInputNamestring"select-search"Name attribute for search input
belowListReactNodeNoneContent rendered below options list
namestringNoneName attribute for the select
startContentReactNodeNoneContent at the start of the trigger button
endContentReactNodeNoneContent at the end of the trigger button
menuMenuConfigNoneMenu configuration overrides (see below)

SelectMenuOption

PropTypeDescription
labelstringDisplay text in the dropdown
valuestring | numberUnique value for the option
disabledbooleanPrevents selection of this option
[key: string]unknownAdditional custom properties

The dropdown menu appearance is controlled through the menu prop, which accepts all MenuConfig options:

PropTypeDefaultDescription
menu.radiusRadius"md"*Corner rounding of the dropdown menu
menu.sizeSize"md"*Size of menu items
menu.itemVariantVariant"ghost"*Visual style of inactive options
menu.itemColorColor"primary"*Color of inactive options
menu.activeItemVariantVariant"faded"*Visual style of selected option
menu.activeItemColorColor"primary"*Color of selected option
menu.lockScrollbooleanfalse*Whether to lock body scroll when open
menu.portalbooleantrue*Whether to render menu in a portal
menu.portalTargetHTMLElement | nullnull*Custom portal target element
menu.classNamestringNoneExtra classes for the dropdown menu

* Falls back through Global Configuration if not set. See below.


Global Configuration

Select reads defaults from four places, in this order of precedence:

  1. Instance prop: set directly on <Select />
  2. Component config: components.select in your ashee.config
  3. Theme default: defaultVariant / defaultColor / defaultRadius in your ashee.config
  4. Built-in fallback: component's internal default values

Component config

ts
// ashee.config.ts
import type { ExternalConfig } from "asheeui";
export const config: ExternalConfig = {
components: {
select: {
size: "md",
radius: "md",
variant: "bordered",
color: "primary",
labelAlign: "left",
menu: {
itemVariant: "ghost",
itemColor: "primary",
activeItemVariant: "faded",
activeItemColor: "primary",
radius: "md",
size: "md",
portal: true,
lockScroll: false,
},
},
},
};

Built-in fallbacks

ts
{
size: "md",
radius: "md",
variant: "bordered",
color: "primary",
status: "default",
labelAlign: "left",
menu: {
itemVariant: "ghost",
itemColor: "primary",
activeItemVariant: "faded",
activeItemColor: "primary",
radius: "md",
size: "md",
portal: true,
lockScroll: false,
},
}

Accessibility

  • Renders a native button trigger with role="listbox" and aria-haspopup
  • Uses aria-expanded to indicate dropdown state
  • Uses aria-invalid for error states
  • Uses aria-disabled for disabled state
  • Supports keyboard navigation through options
  • Search input is accessible via standard input semantics
  • Implements focus-visible rings for keyboard navigation

Portal Behavior

The Select dropdown menu is rendered in a React portal by default. This means the menu is attached to document.body rather than staying in the component's DOM hierarchy.

Why use a portal?

  • Escapes CSS containment: The menu appears above other content even when inside containers with overflow: hidden or contain: layout
  • Avoids stacking context issues: The menu maintains proper z-index regardless of parent stacking contexts
  • Works with any parent: The menu functions correctly regardless of where the Select is placed in the component tree
  • Prevents clipping: The menu is never clipped by parent containers

When to disable the portal

You may want to disable the portal (by setting menu.portal={false}) when:

  • You need the menu to stay within a specific container for testing purposes
  • You are rendering inside a shadow DOM or iframe where document.body is not appropriate
  • You have specific layout requirements that depend on the menu remaining in the DOM hierarchy

You can also provide a custom menu.portalTarget to render the menu into a specific container instead of document.body.


Notes

  • Controlled vs Uncontrolled: Use value/onValueChange for controlled usage, or initialValue for uncontrolled.
  • Search: Enable search with isSearch={true}. The search input filters options in real-time.
  • Placeholder: The placeholder text is shown when no option is selected.
  • Below List: The belowList prop is useful for adding "Add new" buttons or additional controls.
  • Menu Styling: The menu appearance can be customized independently from the trigger using the menu prop.
  • Portal: The dropdown menu is portaled to document.body by default. This can be disabled via the menu.portal prop or component config.
  • Inheritance: Select inherits most Input props but uses a Button as the trigger.
Previous

← ResizableScreen

Next

Sidebar →