SelectTrigger
Build custom select triggers with full control over input and display
You are reading the v1 docs. v2 renamed several props and replaced GeckoUIPortal with GeckoUIProvider. Read this page in v2.
Live examples are only rendered in the v2 docs.
SelectTrigger
SelectTrigger is a render prop component that gives you complete control over the select button/trigger appearance. Build custom search inputs, chip displays, and complex multi-select interfaces.
Basic Custom Trigger
Replace the default select button with a custom input and chip display:
'use client';
import { useState } from 'react';
import { Select, SelectOption, SelectTrigger, Input } from '@geckoui/geckoui';
function Example() {
const [values, setValues] = useState<number[]>([]);
return (
<Select multiple value={values} onChange={setValues}>
<SelectTrigger<number> multiple>
{({
keyword,
selectedOptions,
handleInputChange,
handleKeyboardInteraction,
openMenu
}) => (
<div>
<Input
placeholder="Search months..."
value={keyword}
onChange={handleInputChange}
onKeyDown={handleKeyboardInteraction}
onFocus={openMenu}
autoComplete="off"
autoCapitalize="off"
autoCorrect="off"
spellCheck={false}
/>
{selectedOptions.length > 0 && (
<div className="mt-2 flex flex-wrap gap-2">
{selectedOptions.map((option) => (
<span
key={option.value}
className="bg-blue-100 text-blue-800 px-2 py-1 rounded text-sm"
>
{option.label}
</span>
))}
</div>
)}
</div>
)}
</SelectTrigger>
{Array.from({ length: 12 }, (_, i) => (
<SelectOption
key={i}
value={i}
label={new Date(0, i).toLocaleString('default', { month: 'long' })}
/>
))}
</Select>
);
}Chips with Remove Buttons
Add remove buttons to each chip:
import { X } from 'lucide-react';
<Select multiple value={values} onChange={setValues}>
<SelectTrigger<number> multiple>
{({
keyword,
selectedOptions,
handleChange,
handleInputChange,
handleKeyboardInteraction,
openMenu
}) => (
<div>
<Input
placeholder="Type to search..."
value={keyword}
onChange={handleInputChange}
onKeyDown={handleKeyboardInteraction}
onFocus={openMenu}
autoComplete="off"
/>
{selectedOptions.length > 0 && (
<div className="mt-2 flex flex-wrap gap-2">
{selectedOptions.map((option) => (
<span
key={option.value}
className="inline-flex items-center gap-1 bg-purple-100 text-purple-800 px-2 py-1 rounded"
>
{option.label}
<button
type="button"
onClick={(e) => {
e.stopPropagation();
handleChange(option.value);
}}
className="hover:bg-purple-200 rounded-full p-0.5"
>
<X className="w-3 h-3" />
</button>
</span>
))}
</div>
)}
</div>
)}
</SelectTrigger>
<SelectOption value="react" label="React" />
<SelectOption value="vue" label="Vue" />
<SelectOption value="angular" label="Angular" />
</Select>Single Select with Custom Trigger
Use SelectTrigger for single selection mode:
const [value, setValue] = useState<string | null>(null);
<Select value={value} onChange={setValue}>
<SelectTrigger>
{({
keyword,
selectedOptions,
handleInputChange,
handleKeyboardInteraction,
openMenu
}) => (
<div className="space-y-2">
<Input
placeholder="Search frameworks..."
value={keyword}
onChange={handleInputChange}
onKeyDown={handleKeyboardInteraction}
onFocus={openMenu}
autoComplete="off"
/>
{selectedOptions && (
<div className="p-2 bg-green-50 border border-green-200 rounded">
<span className="text-sm text-green-800">
Selected: <strong>{selectedOptions.label}</strong>
</span>
</div>
)}
</div>
)}
</SelectTrigger>
<SelectOption value="next" label="Next.js" />
<SelectOption value="remix" label="Remix" />
</Select>Note: For single select, selectedOptions is a single object, not an array.
Custom Styled Chips
Use Button components for chips:
import { Button } from '@geckoui/geckoui';
<Select multiple value={values} onChange={setValues}>
<SelectTrigger<number> multiple>
{({ selectedOptions, handleChange, /* ... */ }) => (
<div className="space-y-3">
<Input placeholder="Select programming languages..." />
{selectedOptions.length > 0 && (
<div>
<div className="text-xs text-gray-500 mb-2">
{selectedOptions.length} selected
</div>
<div className="flex flex-wrap gap-2">
{selectedOptions.map((option) => (
<Button
key={option.value}
type="button"
variant="outlined"
size="sm"
onClick={(e) => {
e.stopPropagation();
handleChange(option.value);
}}
className="gap-2"
>
<span>{option.label}</span>
<X className="w-3 h-3" />
</Button>
))}
</div>
</div>
)}
</div>
)}
</SelectTrigger>
{/* ... options */}
</Select>Props API
| Prop | Type | Description |
|---|---|---|
multiple | boolean | Must match the Select's multiple prop |
children | (args) => ReactNode | Render function receiving trigger state |
Render Function Arguments
For Multiple Select (multiple={true})
{
keyword: string;
selectedOptions: Array<{ label: string; value: T }>;
handleChange: (value: T) => void;
options: Array<{ label: string; value: T; /* ... */ }>;
toggleMenu: () => void;
open: boolean;
openMenu: () => void;
closeMenu: () => void;
hasValue: boolean;
filteredOptions: Array<{ label: string; value: T; /* ... */ }>;
handleInputChange: (e: ChangeEvent<HTMLInputElement>) => void;
handleKeyboardInteraction: (e: KeyboardEvent<HTMLInputElement>) => void;
}For Single Select (multiple={false} or omitted)
{
keyword: string;
selectedOptions: { label: string; value: T } | null;
handleChange: (value: T) => void;
// ... same as multiple
}Key difference: selectedOptions is an array for multiple select, but a single object (or null) for single select.
Keyboard Navigation
The handleKeyboardInteraction function handles:
- Arrow Up/Down: Navigate options
- Enter: Select focused option.
- Tab: Navigate options.
- Escape: Close menu (handled by Select)
Always attach it to your input:
<Input
onKeyDown={handleKeyboardInteraction}
// ... other props
/>Best Practices
- Always include
autoComplete="off"on custom inputs to prevent browser suggestions - Use
e.stopPropagation()on chip remove buttons to prevent menu toggling - Match
multipleprop on SelectTrigger with Select'smultipleprop - Handle both keyboard and mouse interactions for accessibility
- Show visual feedback for selected items and focus states
Related Pages
- Multiple Selection - Multi-select patterns
- Filterable - Built-in search without custom trigger
- SelectOption - Customize option display
- Advanced - Programmatic control with useSelect hook