--- title: "Select Field" aliases: [select-field, multi-select, dropdown-field] tags: [payloadcms, fields, select, enum, dropdown] sources: [raw/fields__select.md] created: 2026-05-15 updated: 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 ```ts 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 ```ts { 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: true` stores an array of values - `isSortable` only works when `hasMany: true` - Postgres creates a separate join table (`dbName` to override its name) ## filterOptions Dynamically filters which options appear in the Admin UI **and** which can be saved: ```ts { 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 `filterOptions` on [[wiki/payloadcms/fields-relationship|Relationship]] / [[wiki/payloadcms/fields-overview|Upload]] 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) ```tsx import type { SelectFieldServerComponent } from 'payload' import { SelectField } from '@payloadcms/ui' export const CustomSelectFieldServer: SelectFieldServerComponent = ({ clientField, path, schemaPath, permissions, }) => ( ) ``` ### Client Component (Field) ```tsx 'use client' import type { SelectFieldClientComponent } from 'payload' import { SelectField } from '@payloadcms/ui' export const CustomSelectFieldClient: SelectFieldClientComponent = (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 - `options` values must use underscores, not hyphens (GraphQL enum constraint) - `hasMany: true` switches storage to an array; Postgres creates a join table - `filterOptions` controls both UI display and what values can be saved — useful for role-based or dependent dropdowns - `enumName` / `dbName` let you control Postgres schema naming explicitly - `isSortable` drag-and-drop only activates when `hasMany: true` - Use `interfaceName` to generate a reusable TypeScript interface and GraphQL type for this field's enum ## Related - [[wiki/payloadcms/fields-radio|Radio Field]] — single-choice alternative with radio-button UI - [[wiki/payloadcms/fields-relationship|Relationship Field]] — link to other documents (also has `filterOptions`) - [[wiki/payloadcms/fields-overview|Fields Overview]] — shared field config, validation, admin options - [[wiki/payloadcms/database-postgres|Database — Postgres]] — enum and join table generation details ## Sources - `raw/fields__select.md` — https://payloadcms.com/docs/fields/select