5.2 KiB
5.2 KiB
| title | aliases | tags | sources | created | updated | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Select Field |
|
|
|
2026-05-15 | 2026-05-15 |
Dropdown-style field storing one or many values from a predefined list. Backed by a database enum (Postgres) or string field.
Basic Config
import type { Field } from 'payload'
export const MySelectField: Field = {
name: 'status',
type: 'select',
options: [
{ label: 'Draft', value: 'draft' },
{ label: 'Published', value: 'published' },
{ label: 'Archived', value: 'archived' },
],
}
Config Options
| Option | Required | Description |
|---|---|---|
name |
✓ | DB property name |
options |
✓ | Array of strings or { label, value } objects |
hasMany |
true → allows multiple selections (stored as array) |
|
filterOptions |
Dynamically filter visible/saveable options | |
enumName |
Custom Postgres enum name (auto-generated if omitted) | |
dbName |
Custom join table name when hasMany: true (Postgres) |
|
unique |
DB-level unique constraint | |
index |
Add index for faster queries | |
localized |
Per-locale values | |
saveToJWT |
Include value in auth JWT | |
defaultValue |
Default option value | |
required |
Require a selection | |
hidden |
Exclude from all APIs (still stored in DB) | |
virtual |
Disable DB storage, or link to relationship | |
interfaceName |
Reusable TS interface + GraphQL type | |
typescriptSchema |
Override TS type generation with JSON schema |
GraphQL constraint: option values must not contain hyphens or special characters — only underscores allowed. Values with special characters are reformatted automatically for GraphQL enums.
hasMany — Multi-Select
{
name: 'selectedFeatures',
type: 'select',
hasMany: true,
admin: {
isClearable: true,
isSortable: true, // drag-and-drop reordering
},
options: [
{ label: 'Metallic Paint', value: 'metallic_paint' },
{ label: 'Alloy Wheels', value: 'alloy_wheels' },
{ label: 'Carbon Fiber Dashboard', value: 'carbon_fiber_dashboard' },
],
}
hasMany: truestores an array of valuesisSortableonly works whenhasMany: true- Postgres creates a separate join table (
dbNameto override its name)
filterOptions
Dynamically filters which options appear in the Admin UI and which can be saved:
{
type: 'select',
options: [
{ label: 'One', value: 'one' },
{ label: 'Two', value: 'two' },
{ label: 'Three', value: 'three' },
],
filterOptions: ({ options, data }) =>
data.disallowOption1
? options.filter(o => (typeof o === 'string' ? o : o.value) !== 'one')
: options,
}
Use cases:
- Admin-only options based on
req.user.role - Dependent dropdowns (city filtered by selected state)
Unlike
filterOptionson wiki/payloadcms/fields-relationship / wiki/payloadcms/fields-overview fields, the return value here is an array of options, not a query constraint.
Admin Options
| Property | Description |
|---|---|
isClearable |
Show a clear/reset button in the UI |
isSortable |
Enable drag-and-drop reordering (requires hasMany: true) |
placeholder |
Custom placeholder text or function |
Custom Components
Server Component (Field)
import type { SelectFieldServerComponent } from 'payload'
import { SelectField } from '@payloadcms/ui'
export const CustomSelectFieldServer: SelectFieldServerComponent = ({
clientField, path, schemaPath, permissions,
}) => (
<SelectField field={clientField} path={path} schemaPath={schemaPath} permissions={permissions} />
)
Client Component (Field)
'use client'
import type { SelectFieldClientComponent } from 'payload'
import { SelectField } from '@payloadcms/ui'
export const CustomSelectFieldClient: SelectFieldClientComponent = (props) => (
<SelectField {...props} />
)
Label Components
Use FieldLabel from @payloadcms/ui for both server and client label overrides — pass label, path, and required from clientField/field.
Key Takeaways
optionsvalues must use underscores, not hyphens (GraphQL enum constraint)hasMany: trueswitches storage to an array; Postgres creates a join tablefilterOptionscontrols both UI display and what values can be saved — useful for role-based or dependent dropdownsenumName/dbNamelet you control Postgres schema naming explicitlyisSortabledrag-and-drop only activates whenhasMany: true- Use
interfaceNameto generate a reusable TypeScript interface and GraphQL type for this field's enum
Related
- wiki/payloadcms/fields-radio — single-choice alternative with radio-button UI
- wiki/payloadcms/fields-relationship — link to other documents (also has
filterOptions) - wiki/payloadcms/fields-overview — shared field config, validation, admin options
- wiki/payloadcms/database-postgres — enum and join table generation details
Sources
raw/fields__select.md— https://payloadcms.com/docs/fields/select