Zaidan

Command Palette

Search for a command to run...

GitHub43

Native Select

A styled native HTML select element with consistent design system integration.

Installation

CLI

Manual

Copy and paste the following code into your project.

import { ChevronDown } from "lucide-solid";
import { type ComponentProps, mergeProps, splitProps } from "solid-js";
import { cn } from "~/lib/utils";
type NativeSelectProps = ComponentProps<"select"> & {
size?: "sm" | "default";
};
function NativeSelect(props: NativeSelectProps) {
const mergedProps = mergeProps({ size: "default" }, props);
const [local, others] = splitProps(mergedProps, ["class", "size"]);
return (
<div
class={cn(
"group/native-select relative z-native-select-wrapper w-fit has-[select:disabled]:opacity-50",
local.class,
)}
data-slot="native-select-wrapper"
data-size={local.size}
>
<select
data-slot="native-select"
data-size={local.size}
class="z-native-select outline-none disabled:pointer-events-none disabled:cursor-not-allowed"
{...others}
/>
<ChevronDown
class="pointer-events-none absolute z-native-select-icon select-none"
data-slot="native-select-icon"
/>
</div>
);
}
function NativeSelectOption(props: ComponentProps<"option">) {
return <option data-slot="native-select-option" {...props} />;
}
function NativeSelectOptGroup(props: ComponentProps<"optgroup">) {
const [local, others] = splitProps(props, ["class"]);
return <optgroup data-slot="native-select-optgroup" class={cn(local.class)} {...others} />;
}
export { NativeSelect, NativeSelectOptGroup, NativeSelectOption };

Examples

Here are the source code of all the examples from the preview page:

Basic

import {
NativeSelect,
NativeSelectOption,
} from "~/components/ui/native-select";
function NativeSelectBasic() {
return (
<Example title="Basic">
<NativeSelect>
<NativeSelectOption value="">Select a fruit</NativeSelectOption>
<NativeSelectOption value="apple">Apple</NativeSelectOption>
<NativeSelectOption value="banana">Banana</NativeSelectOption>
<NativeSelectOption value="blueberry">Blueberry</NativeSelectOption>
<NativeSelectOption value="grapes" disabled>
Grapes
</NativeSelectOption>
<NativeSelectOption value="pineapple">Pineapple</NativeSelectOption>
</NativeSelect>
</Example>
);
}

With Groups

Organize options using NativeSelectOptGroup for better categorization.

import {
NativeSelect,
NativeSelectOptGroup,
NativeSelectOption,
} from "~/components/ui/native-select";
function NativeSelectWithGroups() {
return (
<Example title="With Groups">
<NativeSelect>
<NativeSelectOption value="">Select a food</NativeSelectOption>
<NativeSelectOptGroup label="Fruits">
<NativeSelectOption value="apple">Apple</NativeSelectOption>
<NativeSelectOption value="banana">Banana</NativeSelectOption>
<NativeSelectOption value="blueberry">Blueberry</NativeSelectOption>
</NativeSelectOptGroup>
<NativeSelectOptGroup label="Vegetables">
<NativeSelectOption value="carrot">Carrot</NativeSelectOption>
<NativeSelectOption value="broccoli">Broccoli</NativeSelectOption>
<NativeSelectOption value="spinach">Spinach</NativeSelectOption>
</NativeSelectOptGroup>
</NativeSelect>
</Example>
);
}

Sizes

The native select supports different sizes for various use cases.

import {
NativeSelect,
NativeSelectOption,
} from "~/components/ui/native-select";
function NativeSelectSizes() {
return (
<Example title="Sizes">
<div class="flex flex-col gap-4">
<NativeSelect size="sm">
<NativeSelectOption value="">Select a fruit</NativeSelectOption>
<NativeSelectOption value="apple">Apple</NativeSelectOption>
<NativeSelectOption value="banana">Banana</NativeSelectOption>
<NativeSelectOption value="blueberry">Blueberry</NativeSelectOption>
</NativeSelect>
<NativeSelect size="default">
<NativeSelectOption value="">Select a fruit</NativeSelectOption>
<NativeSelectOption value="apple">Apple</NativeSelectOption>
<NativeSelectOption value="banana">Banana</NativeSelectOption>
<NativeSelectOption value="blueberry">Blueberry</NativeSelectOption>
</NativeSelect>
</div>
</Example>
);
}

With Field

Use with the Field component for proper form labeling and descriptions.

import { Field, FieldDescription, FieldLabel } from "~/components/ui/field";
import {
NativeSelect,
NativeSelectOption,
} from "~/components/ui/native-select";
function NativeSelectWithField() {
return (
<Example title="With Field">
<Field>
<FieldLabel for="native-select-country">Country</FieldLabel>
<NativeSelect id="native-select-country">
<NativeSelectOption value="">Select a country</NativeSelectOption>
<NativeSelectOption value="us">United States</NativeSelectOption>
<NativeSelectOption value="uk">United Kingdom</NativeSelectOption>
<NativeSelectOption value="ca">Canada</NativeSelectOption>
<NativeSelectOption value="au">Australia</NativeSelectOption>
</NativeSelect>
<FieldDescription>Select your country of residence.</FieldDescription>
</Field>
</Example>
);
}

Disabled

Disable individual options or the entire select component.

import {
NativeSelect,
NativeSelectOption,
} from "~/components/ui/native-select";
function NativeSelectDisabled() {
return (
<Example title="Disabled">
<NativeSelect disabled>
<NativeSelectOption value="">Disabled</NativeSelectOption>
<NativeSelectOption value="apple">Apple</NativeSelectOption>
<NativeSelectOption value="banana">Banana</NativeSelectOption>
<NativeSelectOption value="blueberry">Blueberry</NativeSelectOption>
</NativeSelect>
</Example>
);
}

Invalid

Show validation errors with the aria-invalid attribute and error styling.

import {
NativeSelect,
NativeSelectOption,
} from "~/components/ui/native-select";
function NativeSelectInvalid() {
return (
<Example title="Invalid">
<NativeSelect aria-invalid="true">
<NativeSelectOption value="">Error state</NativeSelectOption>
<NativeSelectOption value="apple">Apple</NativeSelectOption>
<NativeSelectOption value="banana">Banana</NativeSelectOption>
<NativeSelectOption value="blueberry">Blueberry</NativeSelectOption>
</NativeSelect>
</Example>
);
}

Native Select vs Select

  • Use NativeSelect when you need native browser behavior, better performance, or mobile-optimized dropdowns.
  • Use Select when you need custom styling, animations, or complex interactions.

The NativeSelect component provides native HTML select functionality with consistent styling that matches your design system.

Accessibility

  • The component maintains all native HTML select accessibility features.
  • Screen readers can navigate through options using arrow keys.
  • The chevron icon is marked as aria-hidden="true" to avoid duplication.
  • Use aria-label or aria-labelledby for additional context when needed.
<NativeSelect aria-label="Choose your preferred language">
<NativeSelectOption value="en">English</NativeSelectOption>
<NativeSelectOption value="es">Spanish</NativeSelectOption>
<NativeSelectOption value="fr">French</NativeSelectOption>
</NativeSelect>