Gecko UIGecko UI
Select

Advanced Usage

Programmatic control with useSelect hook and SelectConsumer

Advanced Usage

Access Select's internal state and methods using SelectConsumer for programmatic control, conditional rendering, and advanced customization patterns.

SelectConsumer

SelectConsumer provides access to Select's context via a render prop. Use it to read state or call methods from anywhere inside the Select component.

Select a framework...
"use client";

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

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

  return (
    <Select value={value} onChange={setValue} filterable placeholder="Select a framework...">
      <SelectConsumer
        render={({ open, keyword, options }) => (
          <div className="p-3 border rounded-md bg-gray-50 dark:bg-neutral-800 text-sm mb-2">
            <p>
              <strong>Status:</strong> {open ? "Open" : "Closed"}
            </p>
            <p>
              <strong>Filter:</strong> {keyword || "(none)"}
            </p>
            <p>
              <strong>Total Options:</strong> {options.length}
            </p>
          </div>
        )}
      />
      <SelectOption value="react" label="React" />
      <SelectOption value="vue" label="Vue" />
      <SelectOption value="angular" label="Angular" />
    </Select>
  );
}

Programmatic Control

Control the menu and selection programmatically:

Select a language...
<Select value={value} onChange={setValue}>
  <SelectConsumer
    render={({ openMenu, closeMenu, open }) => (
      <div className="flex gap-2 mb-2">
        <Button onClick={openMenu} disabled={open}>
          Open Menu
        </Button>
        <Button onClick={closeMenu} disabled={!open}>
          Close Menu
        </Button>
        <Button
          onClick={() => {
            setValue("python");
            closeMenu();
          }}>
          Select Python
        </Button>
      </div>
    )}
  />
  <SelectOption value="typescript" label="TypeScript" />
  <SelectOption value="javascript" label="JavaScript" />
  <SelectOption value="python" label="Python" />
</Select>

Conditional Rendering

Show/hide UI based on Select state:

Select tags...
<Select multiple value={values} onChange={setValues}>
  <SelectConsumer
    render={({ keyword, options, isSelected }) => {
      const selectedCount = options.filter((opt) => isSelected(opt.value)).length;
      const filteredCount = keyword
        ? options.filter((opt) => opt.label.toLowerCase().includes(keyword.toLowerCase())).length
        : options.length;

      return (
        <div className="p-2 border-b mb-2 text-sm text-gray-600">
          <div className="flex justify-between">
            <span>Selected: {selectedCount}</span>
            {keyword && <span>Matching: {filteredCount}</span>}
          </div>
        </div>
      );
    }}
  />
  <SelectOption value="bug" label="Bug" />
  <SelectOption value="feature" label="Feature" />
  <SelectOption value="docs" label="Documentation" />
</Select>

Custom Quick Actions

Add quick action buttons inside the dropdown:

Select a status...
<Select value={value} onChange={setValue}>
  <SelectConsumer<string>
    render={({ handleChange, closeMenu, value: currentValue }) => (
      <div className="p-2 border-t mt-2 flex gap-2">
        <Button
          size="sm"
          variant="ghost"
          onClick={() => {
            handleChange("active");
            closeMenu();
          }}>
          Quick: Active
        </Button>
        <Button
          size="sm"
          variant="ghost"
          onClick={() => {
            handleChange("inactive");
            closeMenu();
          }}>
          Quick: Inactive
        </Button>
        {currentValue && (
          <Button
            size="sm"
            variant="ghost"
            onClick={() => {
              setValue(null);
              closeMenu();
            }}>
            Clear
          </Button>
        )}
      </div>
    )}
  />
  <SelectOption value="active" label="Active" />
  <SelectOption value="inactive" label="Inactive" />
  <SelectOption value="pending" label="Pending" />
</Select>

Debug View

Inspect Select's internal state during development:

Option 1

Debug Info:

opt1
<Select multiple value={values} onChange={setValues}>
  <SelectConsumer
    render={({ open, keyword, value, multiple, options, focusedOption }) => (
      <pre className="text-xs bg-gray-50 dark:bg-neutral-800 p-3 rounded border">
        {JSON.stringify(
          {
            open,
            keyword,
            value,
            multiple,
            totalOptions: options.length,
            focusedOption: focusedOption?.label || null
          },
          null,
          2
        )}
      </pre>
    )}
  />
  <SelectOption value="opt1" label="Option 1" />
  <SelectOption value="opt2" label="Option 2" />
</Select>

useSelect Hook

For building completely custom Select components, use the useSelect hook directly:

import { useSelect } from "@geckoui/geckoui";

function CustomSelectComponent() {
  const {
    open,
    openMenu,
    closeMenu,
    toggleMenu,
    keyword,
    setKeyword,
    value,
    handleChange,
    isSelected,
    options,
    focusedOption,
    setFocusedOption,
    isEmpty,
    floating,
    inputRef,
    setInputRef
  } = useSelect<string>();

  // Build your custom UI here
  return <div>{/* Custom implementation */}</div>;
}

// Must be used inside a Select component
<Select value={value} onChange={setValue}>
  <CustomSelectComponent />
</Select>;

Important: useSelect must be called inside a Select component (it uses React Context).

Available Context Properties

State

PropertyTypeDescription
openbooleanWhether dropdown is open
keywordstringCurrent filter keyword
valueT | T[]Current selected value(s)
multiplebooleanWhether in multiple selection mode
isEmptybooleanWhether no options match filter
disabledbooleanWhether Select is disabled
placeholderstringPlaceholder text
closeMenuOnSelectbooleanAuto-close behavior

Data

PropertyTypeDescription
optionsSelectOptionConfig<T>[]All available options
focusedOptionFocusedOption<T> | nullCurrently focused option

Methods

MethodTypeDescription
openMenu() => voidOpen the dropdown
closeMenu() => voidClose the dropdown
toggleMenu() => voidToggle dropdown state
handleChange(value: T) => voidSelect/deselect an option
isSelected(value: T) => booleanCheck if option is selected
setKeyword(keyword: string) => voidUpdate filter keyword
setOpen(open: boolean) => voidSet open state directly
setFocusedOption(option: FocusedOption<T>) => voidSet focused option

Advanced

PropertyTypeDescription
floatingUseFloatingReturnFloating UI positioning data
inputRefRefObject<HTMLInputElement>Ref for filter input
setInputRef(ref: any) => RefCallbackSet input ref callback
prefixReactNodePrefix content
suffixReactNodeSuffix content

When to Use

Use SelectConsumer/useSelect when you need to:

  • Build completely custom Select UI
  • Access internal state for debugging
  • Sync Select state with external systems
  • Create conditional rendering based on Select state

When NOT to Use

Don't use SelectConsumer when:

  • SelectTrigger can solve your custom trigger needs
  • SelectOption custom content is sufficient
  • You just need custom empty states (use SelectEmpty)
  • You want basic filtering (use filterable prop)