ReactSelectCreatableField
Description
An enhanced select field that allows users to create new options dynamically. Built on react-select's CreatableSelect component, it combines search, multi-select, and the ability to add custom values not in the initial options list.
Import
import { ReactSelectCreatableField } from '@components/common/form/ReactSelectCreatableField';
Usage
import { Form } from '@components/common/form/Form';
import { ReactSelectCreatableField } from '@components/common/form/ReactSelectCreatableField';
function ProductForm() {
const tagOptions = [
{ value: 'electronics', label: 'Electronics' },
{ value: 'gadgets', label: 'Gadgets' }
];
return (
<Form action="/api/products">
<ReactSelectCreatableField
name="tags"
label="Tags"
options={tagOptions}
isMulti={true}
placeholder="Select or create tags..."
/>
</Form>
);
}
Props
| Name | Type | Default | Description |
|---|---|---|---|
| name | FieldPath<T> | - | Field name (required) |
| options | SelectOption[] | - | Initial array of options (required) |
| label | string | - | Label text displayed above the select |
| placeholder | string | - | Placeholder text when no option is selected |
| isMulti | boolean | false | Enable multiple selection |
| onCreateOption | (inputValue: string) => void | - | Callback when a new option is created |
| formatCreateLabel | (inputValue: string) => string | (val) => Create "${val}" | Format the "create" option label |
| isSearchable | boolean | true | Enable search/filter functionality |
| isClearable | boolean | false | Show clear button to remove selection |
| isDisabled | boolean | false | Disable the select |
| defaultValue | any | - | Default selected value(s) |
| required | boolean | false | Makes the field required |
| error | string | - | Custom error message |
| helperText | string | - | Helper text shown below the select |
| validation | RegisterOptions<T> | - | React Hook Form validation rules |
| wrapperClassName | string | 'form-field' | CSS class for the wrapper div |
SelectOption Interface
interface SelectOption {
value: any;
label: string;
[key: string]: any;
}
Example: Multi-Select Tags
import { Form } from '@components/common/form/Form';
import { ReactSelectCreatableField } from '@components/common/form/ReactSelectCreatableField';
function BlogPostForm() {
const existingTags = [
{ value: 'javascript', label: 'JavaScript' },
{ value: 'react', label: 'React' },
{ value: 'typescript', label: 'TypeScript' }
];
return (
<Form action="/api/posts">
<ReactSelectCreatableField
name="tags"
label="Tags"
options={existingTags}
isMulti={true}
placeholder="Select or create tags..."
helperText="Type to create new tags"
/>
</Form>
);
}
Example: With Create Callback
import { Form } from '@components/common/form/Form';
import { ReactSelectCreatableField } from '@components/common/form/ReactSelectCreatableField';
function CategoryForm() {
const [categories, setCategories] = useState([
{ value: 'electronics', label: 'Electronics' },
{ value: 'books', label: 'Books' }
]);
const handleCreateCategory = (inputValue: string) => {
console.log('New category created:', inputValue);
// You can perform additional actions like API calls here
};
return (
<Form action="/api/products">
<ReactSelectCreatableField
name="category"
label="Category"
options={categories}
onCreateOption={handleCreateCategory}
placeholder="Select or create category..."
/>
</Form>
);
}
Example: Custom Create Label
import { Form } from '@components/common/form/Form';
import { ReactSelectCreatableField } from '@components/common/form/ReactSelectCreatableField';
function SkillsForm() {
const skillOptions = [
{ value: 'html', label: 'HTML' },
{ value: 'css', label: 'CSS' },
{ value: 'js', label: 'JavaScript' }
];
return (
<Form action="/api/profile">
<ReactSelectCreatableField
name="skills"
label="Skills"
options={skillOptions}
isMulti={true}
formatCreateLabel={(input) => `Add skill: ${input}`}
placeholder="Select or add skills..."
/>
</Form>
);
}
Example: With Validation
import { Form } from '@components/common/form/Form';
import { ReactSelectCreatableField } from '@components/common/form/ReactSelectCreatableField';
function EmailForm() {
const recipientOptions = [
{ value: 'team@example.com', label: 'Team' },
{ value: 'support@example.com', label: 'Support' }
];
return (
<Form action="/api/emails">
<ReactSelectCreatableField
name="recipients"
label="Recipients"
options={recipientOptions}
isMulti={true}
required={true}
validation={{
required: 'At least one recipient is required',
validate: (value) =>
value?.length > 0 || 'Please add at least one recipient'
}}
placeholder="Select or add email addresses..."
/>
</Form>
);
}
How New Options Are Created
When a user types a value not in the options list and presses Enter:
- A new option is created with:
value: lowercase input with non-alphanumeric characters removedlabel: the original input value
- The new option is added to the dynamic options list
- The
onCreateOptioncallback is called (if provided) - For single-select: the new value is set as the field value
- For multi-select: the new value is added to the array
Dependencies
This component uses react-select/creatable from the react-select library. The library is included in EverShop dependencies.
Features
- Dynamic Option Creation: Users can add new options on-the-fly
- Searchable: Type to filter existing options
- Multi-Select Support: Select multiple values including created ones
- Duplicate Prevention: Prevents creating duplicate options
- Custom Create Label: Customize how the "create" prompt appears
- Create Callback: Hook into option creation for API calls or logging
- Value Normalization: Automatically normalizes created values
- Controller Integration: Uses React Hook Form Controller
- Auto-cleanup: Unregisters field on unmount
Value Format
Created option values are normalized:
- Convert to lowercase
- Remove non-alphanumeric characters
- Example: "New Tag!" becomes "newtag" as value, but displays as "New Tag!"
Styling
Inherits the same styling as ReactSelectField:
- Gray border with blue focus ring
- Custom styles for control and input
- Integrates with form error states
Related Components
- Form - Parent form component
- ReactSelectField - Enhanced select without create option
- SelectField - Native HTML select