Skip to content

Select (components/ui/select.tsx)

Overview

A customizable select component built with Radix UI that provides accessible dropdown selection functionality.

Features

  • Option groups
  • Placeholder support
  • Custom triggers
  • Search functionality
  • Keyboard navigation
  • Focus management
  • Animation effects
  • Accessibility support
  • Responsive design
  • Error state handling

Dependencies

import * as React from 'react'
import * as SelectPrimitive from '@radix-ui/react-select'
import { Check, ChevronDown } from 'lucide-react'
import { cn } from '@/lib/utils'

Props

interface SelectProps extends SelectPrimitive.SelectProps {
  placeholder?: string;
  error?: boolean;
  className?: string;
  children: ReactNode;
}

interface SelectTriggerProps extends SelectPrimitive.SelectTriggerProps {
  className?: string;
  children: ReactNode;
}

interface SelectContentProps extends SelectPrimitive.SelectContentProps {
  className?: string;
  children: ReactNode;
}

interface SelectItemProps extends SelectPrimitive.SelectItemProps {
  className?: string;
  children: ReactNode;
}

interface SelectGroupProps extends SelectPrimitive.SelectGroupProps {
  className?: string;
  children: ReactNode;
}

Implementation

State Management

const [open, setOpen] = useState(false);
const [value, setValue] = useState('');

const handleValueChange = (value: string) => {
  setValue(value);
  onChange?.(value);
};

const handleOpenChange = (open: boolean) => {
  setOpen(open);
  onOpenChange?.(open);
};

Methods

const handleKeyDown = (event: React.KeyboardEvent) => {
  if (event.key === 'Enter' || event.key === ' ') {
    event.preventDefault();
    setOpen(true);
  }
};

const handleBlur = () => {
  setOpen(false);
};

Unique Functionality

  • Option group handling
  • Value management
  • Focus control
  • Animation states
  • Position calculation
  • Error state handling

HTML Structure

<SelectPrimitive.Root
  open={open}
  onOpenChange={handleOpenChange}
  value={value}
  onValueChange={handleValueChange}
>
  <SelectPrimitive.Trigger
    className={cn(
      "flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
      error && "border-destructive focus:ring-destructive",
      className
    )}
    onKeyDown={handleKeyDown}
    onBlur={handleBlur}
  >
    <SelectPrimitive.Value placeholder={placeholder} />
    <SelectPrimitive.Icon>
      <ChevronDown className="h-4 w-4 opacity-50" />
    </SelectPrimitive.Icon>
  </SelectPrimitive.Trigger>

  <SelectPrimitive.Portal>
    <SelectPrimitive.Content
      className={cn(
        "relative z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md animate-in fade-in-80",
        position === "popper" && "translate-y-1",
        className
      )}
      position={position}
      {...props}
    >
      <SelectPrimitive.Viewport className="p-1">
        {children}
      </SelectPrimitive.Viewport>
    </SelectPrimitive.Content>
  </SelectPrimitive.Portal>
</SelectPrimitive.Root>

API Integration

No direct API integration required.

Components Used

  • Select
  • SelectGroup
  • SelectValue
  • SelectTrigger
  • SelectContent
  • SelectLabel
  • SelectItem
  • SelectSeparator

Notes

  • Built on Radix UI primitives
  • Handles keyboard navigation
  • Manages focus states
  • Supports option groups
  • Provides custom triggers
  • Maintains accessibility features
  • Uses React Portal for rendering