Select

A native select component with consistent styling across browsers.

Source Code

"use client";
 
import { VariantProps } from "cva";
 
import { cn } from "@/lib/utils";
 
import {
  InputGroup,
  InputPrefix,
  inputStyle,
} from "@/components/input";
 
interface SelectProps extends React.ComponentPropsWithRef<"select"> {
  invalid?: boolean;
  variant?: VariantProps<typeof inputStyle>["variant"];
}
 
const Select = ({ className, invalid, variant, ...props }: SelectProps) => {
  return (
    <select
      data-invalid={invalid}
      className={cn(
        inputStyle({ variant }),
        "appearance-none bg-[length:1em] bg-[position:right_--spacing(2)_center] bg-no-repeat pr-10",
        'bg-[url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDE2IDE2Ij48cGF0aCBmaWxsPSJibGFjayIgZD0iTTMuNyA1LjNsNC4zIDQuMyA0LjMtNC4zLjcuNy01IDUtNS01eiIvPjwvc3ZnPg==")]',
        'dark:bg-[url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDE2IDE2Ij48cGF0aCBmaWxsPSJ3aGl0ZSIgZD0iTTMuNyA1LjNsNC4zIDQuMyA0LjMtNC4zLjcuNy01IDUtNS01eiIvPjwvc3ZnPg==")]',
        className
      )}
      {...props}
    />
  );
};
 
const SelectGroup = InputGroup;
 
const SelectPrefix = InputPrefix;
 
export { Select, SelectGroup, SelectPrefix };

Features

  • Native Element: Uses the browser's native select element for optimal mobile support
  • Consistent Styling: Normalized appearance across different browsers
  • Form Integration: Works seamlessly with form libraries and native form validation
  • Prefix Support: Optional prefix for additional context
  • Variants: Supports default and minimal visual styles
  • Validation: Built-in invalid state styling

Anatomy

<SelectGroup>
  <SelectPrefix />
  <Select>
    <option>
  </Select>
</SelectGroup>

API Reference

Select

Extends the select element.

PropDefaultTypeDescription

variant

"default"

"default"

"minimal"

The visual style variant to use.

invalid

false

boolean

Whether the select is in an invalid state.

SelectGroup

Extends the div element.

A wrapper component that provides proper spacing and layout for the select and its prefix.

SelectPrefix

Extends the div element.

PropDefaultTypeDescription

interactive

false

boolean

When true, the prefix can be clicked and will receive focus.

Accessibility

The Select component uses the native <select> element, which provides excellent accessibility out of the box:

  • Full keyboard navigation support
  • Screen reader announcements
  • Mobile-friendly interaction
  • Native form integration

Examples

Simple

Basic usage with a list of options.

Minimal

Using the minimal variant without borders.

Disabled

The select in a disabled state.

Invalid

The select showing an invalid state.

Prefix

Using a prefix to provide additional context.

Best Practices

  1. Use Listbox for Complex Cases:

    • If you need custom option rendering
    • If you need search functionality
    • If you need multiple selection
    • If you need complex keyboard interactions
  2. Mobile Considerations:

    • The native select provides the best experience on mobile devices
    • It automatically adapts to the platform's native picker
  3. Form Integration:

    • Use the required attribute for required fields
    • Use the name attribute for form submission
    • Use the invalid prop in conjunction with form validation
  4. Accessibility:

    • Always provide a visible label or aria-label
    • Group related selects with fieldset and legend
    • Use aria-describedby for additional descriptions