Gecko UIGecko UI
Select

Select

Customizable dropdown select component with single selection mode

Select

A customizable select dropdown component with support for single and multiple selections, keyboard navigation, search filtering, and custom positioning. Built with floating-ui for intelligent dropdown placement.

Installation

import { Select, SelectOption } from "@geckoui/geckoui";

Basic Usage

Select Item
"use client";

import { Select, SelectOption } from "@geckoui/geckoui";
import { useState } from "react";

function Example() {
  const [value, setValue] = useState<string | null>(null);

  return (
    <Select value={value} onChange={setValue}>
      <SelectOption value="react" label="React" />
      <SelectOption value="vue" label="Vue" />
      <SelectOption value="angular" label="Angular" />
    </Select>
  );
}

Important: Use null or undefined for no selection. An empty string "" is considered a valid value and will try to match against options.

Props API

PropTypeDefaultDescription
valueT | null-Selected value (required)
onChange(value: T | null) => void-Callback when selection changes (required)
placeholderstring-Placeholder text when empty
disabledbooleanfalseDisable the select
closeMenuOnSelectbooleantrueClose menu after selection
placementPlacement'bottom-start'Menu placement position
floatingStrategyStrategy-Floating positioning strategy
wrapperClassNamestring-CSS class for wrapper
menuClassNamestring-CSS class for menu
placeholderClassNamestring-CSS class for placeholder
classNamestring-CSS class for select button
filterableboolean | 'inline' | 'dropdown'falseEnable search filtering
multiplebooleanfalseEnable multiple selection
hideDefaultEmptyUIbooleanfalseHide default empty state
inputRefRefObject-Ref for filter input
prefixReactNode-Content before select button
suffixReactNode-Content after select button

Examples

With Placeholder

Choose a framework...
const [value, setValue] = useState<string | null>(null);

<Select value={value} onChange={setValue} placeholder="Choose a framework...">
  <SelectOption value="next" label="Next.js" />
  <SelectOption value="remix" label="Remix" />
  <SelectOption value="gatsby" label="Gatsby" />
</Select>;

Disabled Options

Select Item
const [value, setValue] = useState<string | null>(null);

<Select value={value} onChange={setValue}>
  <SelectOption value="available" label="Available Option" />
  <SelectOption value="disabled" label="Disabled Option" disabled />
  <SelectOption value="another" label="Another Available" />
</Select>;

Disabled Select

Selected Option
<Select value="selected" onChange={() => {}} disabled>
  <SelectOption value="selected" label="Selected Option" />
  <SelectOption value="other" label="Other Option" />
</Select>

Placement Options

Select Item
Select Item
const [value, setValue] = useState<string | null>(null);

// Opens upward
<Select value={value} onChange={setValue} placement="top-start">
  <SelectOption value="a" label="Choice A" />
  <SelectOption value="b" label="Choice B" />
</Select>

// Aligns to right
<Select value={value} onChange={setValue} placement="bottom-end">
  <SelectOption value="a" label="Choice A" />
  <SelectOption value="b" label="Choice B" />
</Select>

Grouped Options with Static Elements

You can add any HTML elements inside Select to create headers, dividers, and footers. These static elements won't interfere with filtering or selection.

Basic Grouping

Select a framework...
const [value, setValue] = useState<string | null>(null);

<Select value={value} onChange={setValue}>
  <div className="px-3 py-2 text-xs font-semibold text-gray-500 uppercase">Frontend</div>
  <SelectOption value="react" label="React" />
  <SelectOption value="vue" label="Vue" />
  <SelectOption value="angular" label="Angular" />

  <hr className="my-1 border-gray-200" />

  <div className="px-3 py-2 text-xs font-semibold text-gray-500 uppercase">Backend</div>
  <SelectOption value="node" label="Node.js" />
  <SelectOption value="django" label="Django" />
  <SelectOption value="rails" label="Rails" />
</Select>;

Grouped with Filterable

Static elements remain visible during filtering:

Search frameworks...
<Select filterable="inline" value={value} onChange={setValue}>
  <div className="px-3 py-2 text-xs font-semibold text-gray-500 uppercase bg-gray-50 dark:bg-neutral-800">
    Frontend Frameworks
  </div>
  <SelectOption value="react" label="React" />
  <SelectOption value="vue" label="Vue" />

  <hr className="my-1 border-gray-200" />

  <div className="px-3 py-2 text-xs font-semibold text-gray-500 uppercase bg-gray-50 dark:bg-neutral-800">
    Backend Frameworks
  </div>
  <SelectOption value="express" label="Express" />
  <SelectOption value="nest" label="NestJS" />
</Select>
Select a color...
<Select value={value} onChange={setValue}>
  <div className="px-3 py-2 border-b bg-gray-50 dark:bg-neutral-800">
    <p className="text-sm font-medium">Choose your favorite color</p>
    <p className="text-xs text-gray-500">This will be used as your theme</p>
  </div>

  <SelectOption value="blue" label="Blue" />
  <SelectOption value="green" label="Green" />
  <SelectOption value="purple" label="Purple" />

  <div className="px-3 py-2 border-t bg-gray-50 dark:bg-neutral-800">
    <a href="#" className="text-xs text-blue-600 hover:underline">
      Customize colors →
    </a>
  </div>
</Select>

Complex Grouping

Select a programming language...
<Select value={value} onChange={setValue}>
  <div className="px-3 py-2 bg-blue-50">
    <p className="text-xs font-semibold text-blue-700">âš¡ Popular</p>
  </div>
  <SelectOption value="javascript" label="JavaScript" />
  <SelectOption value="python" label="Python" />

  <div className="px-3 py-2 bg-green-50 mt-1">
    <p className="text-xs font-semibold text-green-700">🚀 Trending</p>
  </div>
  <SelectOption value="rust" label="Rust" />
  <SelectOption value="go" label="Go" />

  <hr className="my-1 border-gray-200" />

  <div className="px-3 py-2">
    <p className="text-xs font-semibold text-gray-500">Others</p>
  </div>
  <SelectOption value="java" label="Java" />
  <SelectOption value="csharp" label="C#" />
</Select>

Static Notes

Select a plan...
<Select value={value} onChange={setValue}>
  <SelectOption value="free" label="Free Plan" />
  <SelectOption value="pro" label="Pro Plan - $29/mo" />
  <SelectOption value="enterprise" label="Enterprise Plan - $99/mo" />

  <div className="px-3 py-2 mt-2 bg-yellow-50 border border-yellow-200 rounded mx-2 mb-2">
    <p className="text-xs text-yellow-800">
      💡 <strong>Tip:</strong> Annual billing saves 20%
    </p>
  </div>
</Select>

Key Points:

  • Static HTML elements (divs, hr, etc.) won't interfere with option selection
  • They remain visible during filtering
  • Useful for headers, dividers, footers, and informational content
  • Style them with any CSS classes

Keyboard Navigation

  • Arrow Up/Down: Navigate options
  • Enter/Space: Select focused option
  • Escape: Close menu
  • Tab: Close menu and move to next element
  • Type to search: Filter options (when filterable enabled)

Accessibility

  • Built with floating-ui for intelligent positioning
  • Fully keyboard navigable
  • Click-outside to close
  • Focus management
  • Works with screen readers
  • ARIA attributes automatically applied

Styling

The component uses BEM-style class names:

  • GeckoUISelect - Main container
  • GeckoUISelectButton - Select button
  • GeckoUISelectMenu - Menu container
  • GeckoUISelectOption - Individual option
  • GeckoUISelectOption--selected - Applied to selected options
  • GeckoUISelectOption--focused - Applied to focused option