SelectInput

SelectInput

The <SelectInput> component is a dropdown select input for choosing from a list of options. It integrates with react-hook-form and supports both static and dynamic choices.

Usage

Use SelectInput with static choices:

import { Edit, SimpleForm, TextInput, SelectInput } from '@/components/admin';

const UserEdit = () => (
  <Edit>
    <SimpleForm>
      <TextInput source="name" />
      <SelectInput
        source="role"
        choices={[
          { id: 'user', name: 'User' },
          { id: 'admin', name: 'Admin' },
          { id: 'moderator', name: 'Moderator' },
        ]}
      />
    </SimpleForm>
  </Edit>
);

Installation

Terminal
npx better-admin add select-input

Props

PropRequiredTypeDefaultDescription
sourceRequiredstring-Field name
choicesRequiredarray-List of options
labelOptionalstringInferredInput label
placeholderOptionalstring"Select..."Placeholder text
helperTextOptionalstring-Help text below input
optionTextOptionalstring | function"name"Field to display for each choice
optionValueOptionalstring"id"Field to use as value
requiredOptionalbooleanfalseMark as required
disabledOptionalbooleanfalseDisable input
validateOptionalValidator[]-Validation rules
allowEmptyOptionalbooleanfalseAllow clearing selection

Choice Format

Choices must have id and name properties by default:

<SelectInput
  source="status"
  choices={[
    { id: 'draft', name: 'Draft' },
    { id: 'published', name: 'Published' },
    { id: 'archived', name: 'Archived' },
  ]}
/>

Custom Option Properties

Use different properties for value and display:

<SelectInput
  source="category_id"
  choices={[
    { value: 1, label: 'Electronics' },
    { value: 2, label: 'Clothing' },
    { value: 3, label: 'Books' },
  ]}
  optionValue="value"
  optionText="label"
/>

Option Text as Function

Customize how options are displayed:

<SelectInput
  source="user_id"
  choices={users}
  optionText={(user) => `${user.name} (${user.email})`}
/>

Allow Empty Selection

Enable clearing the selection:

<SelectInput
  source="category"
  choices={categories}
  allowEmpty
  placeholder="Select a category..."
/>

With Validation

Add validation rules:

import { required } from '@/lib/validators';

<SelectInput
  source="status"
  choices={statusChoices}
  validate={required('Status is required')}
  required
/>

Helper Text

Add helpful information:

<SelectInput
  source="priority"
  choices={[
    { id: 'low', name: 'Low' },
    { id: 'medium', name: 'Medium' },
    { id: 'high', name: 'High' },
  ]}
  helperText="Choose task priority level"
/>

With better-query

Use with better-query for dynamic choices:

import { Edit, SimpleForm, TextInput, SelectInput } from '@/components/admin';
import { useQuery } from 'better-admin';
import { query } from '@/lib/query';

export function PostEdit({ id }: { id: string }) {
  const { data: post, update } = useQuery("post", query);
  const { data: categories } = useQuery("category", query);

  return (
    <Edit
      resource="post"
      id={id}
      onSubmit={(values) => {
        update.mutate({
          where: { id },
          data: values,
        });
      }}
    >
      <SimpleForm>
        <TextInput source="title" required />
        <SelectInput
          source="category_id"
          choices={categories || []}
          required
        />
        <SelectInput
          source="status"
          choices={[
            { id: 'draft', name: 'Draft' },
            { id: 'published', name: 'Published' },
            { id: 'archived', name: 'Archived' },
          ]}
          required
        />
      </SimpleForm>
    </Edit>
  );
}

Grouped Options

Create option groups:

<SelectInput
  source="fruit"
  choices={[
    { id: 'citrus', name: 'Citrus', group: 'Category' },
    { id: 'orange', name: 'Orange', group: 'Citrus' },
    { id: 'lemon', name: 'Lemon', group: 'Citrus' },
    { id: 'berry', name: 'Berries', group: 'Category' },
    { id: 'strawberry', name: 'Strawberry', group: 'Berries' },
  ]}
/>

Disabled Options

Disable specific options:

<SelectInput
  source="plan"
  choices={[
    { id: 'free', name: 'Free', disabled: false },
    { id: 'pro', name: 'Pro', disabled: false },
    { id: 'enterprise', name: 'Enterprise', disabled: true }, // Coming soon
  ]}
/>

Complete Example

import {
  Create,
  SimpleForm,
  TextInput,
  NumberInput,
  SelectInput,
} from '@/components/admin';
import { useQuery } from 'better-admin';
import { query } from '@/lib/query';
import { required, min } from '@/lib/validators';

export function ProductCreate() {
  const { create } = useQuery("product", query);
  const { data: categories } = useQuery("category", query);
  const { data: suppliers } = useQuery("supplier", query);

  return (
    <Create
      resource="product"
      onSubmit={(values) => {
        create.mutate({ data: values });
      }}
    >
      <SimpleForm>
        <TextInput 
          source="name" 
          validate={required()}
          required 
        />
        
        <SelectInput
          source="category_id"
          choices={categories || []}
          validate={required()}
          required
          helperText="Product category"
        />
        
        <SelectInput
          source="supplier_id"
          choices={suppliers || []}
          optionText={(supplier) => `${supplier.name} (${supplier.country})`}
          allowEmpty
          helperText="Optional supplier"
        />
        
        <NumberInput 
          source="price" 
          step={0.01}
          min={0}
          validate={[required(), min(0.01)]}
          required
        />
        
        <SelectInput
          source="status"
          choices={[
            { id: 'active', name: 'Active' },
            { id: 'inactive', name: 'Inactive' },
            { id: 'discontinued', name: 'Discontinued' },
          ]}
          required
          helperText="Product availability status"
        />
        
        <SelectInput
          source="unit"
          choices={[
            { id: 'piece', name: 'Piece' },
            { id: 'kg', name: 'Kilogram' },
            { id: 'liter', name: 'Liter' },
            { id: 'box', name: 'Box' },
          ]}
          required
        />
      </SimpleForm>
    </Create>
  );
}

With Dependencies

Create dependent selects:

import { SelectInput } from '@/components/admin';
import { useWatch } from 'react-hook-form';

export function DependentSelects() {
  const country = useWatch({ name: 'country' });
  
  const getCities = (country: string) => {
    // Return cities based on selected country
    if (country === 'us') {
      return [
        { id: 'ny', name: 'New York' },
        { id: 'la', name: 'Los Angeles' },
      ];
    }
    return [];
  };

  return (
    <>
      <SelectInput
        source="country"
        choices={[
          { id: 'us', name: 'United States' },
          { id: 'ca', name: 'Canada' },
        ]}
      />
      
      <SelectInput
        source="city"
        choices={getCities(country)}
        disabled={!country}
      />
    </>
  );
}

Next Steps

On this page