- Payload CMS Admin UI Components: Complete Glossary
Payload CMS Admin UI Components: Complete Glossary
Authoritative reference for @payloadcms/ui elements & fields (v3.6+). Props, imports, usage examples, and best…

Need Help Making the Switch?
Moving to Next.js and Payload CMS? I offer advisory support on an hourly basis.
Book Hourly AdvisoryRelated Posts:
This living reference catalogues the high-usage UI primitives exposed by @payloadcms/ui so custom admin extensions can look native. It complements the walkthrough in docs/guides/building-custom-admin-ui-payload-cms-v3.md and will grow as we document additional components.
Using This Reference
- Scope: v3.6+ Payload projects using the Next.js App Router in
src/appwith custom admin extensions in(payload)routes. - Audience: developers building bespoke field types, layout chrome, and admin embeds who need parity with Payload styles and behavior.
- Maintenance: update version notes and props when bumping Payload; add new components as they enter regular use.
How to Explore @payloadcms/ui
- Type definitions: Browse
node_modules/@payloadcms/ui/dist/elements/*anddist/fields/*for.d.tsfiles that declare props, default behaviors, and helper exports. - Source inspection: Many components re-export JSX from nearby
index.jsfiles—quickly open them to confirm transitions, context requirements, or composed children. - CSS classes: Each folder ships a matching
.scssfile. Copy class names (e.g.,array-field,pill,tooltip) instead of inventing new selectors. - Local examples: The bulk inventory table component at
src/components/fields/InventoryBatchBulkTable.tsxshows how these pieces fit together in production.
Import Conventions
- Elements live under
@payloadcms/ui/elements/<Component>. - Field primitives live under
@payloadcms/ui/fields/<Component>. - Hooks such as
useFieldcome from the package root:import { useField } from '@payloadcms/ui'. - Most components are safe in both client and server components, but anything that depends on browser APIs (e.g., drag-and-drop, drawers) must be marked
'use client'at the file top.
Elements
Button (@payloadcms/ui/elements/Button)
Role: Primary action trigger with design-system variants and optional icons.
Import
import { Button } from '@payloadcms/ui/elements/Button'
Key props
| prop | type | notes |
|---|---|---|
buttonStyle | `'primary' | 'secondary' |
size | `'xsmall' | 'small' |
icon | `'chevron' | 'edit' |
iconPosition | `'left' | 'right'` |
programmaticSubmit | boolean | Forces form submission for detached buttons. |
secondaryActions | `secondaryAction | secondaryAction[]` |
Usage
<Button
buttonStyle="primary"
size="medium"
icon="plus"
iconPosition="left"
onClick={onAddRow}
>
Add another row
</Button>
Tips
- Prefer
buttonStyle="primary"for a single dominant action per block. - Use the
tooltipprop for icon-only buttons to preserve accessibility.
Card (@payloadcms/ui/elements/Card)
Role: Clickable summary tile with title and optional CTA area.
Import
import { Card } from '@payloadcms/ui/elements/Card'
Key props
| prop | type | notes |
|---|---|---|
title | string | Required heading text. |
actions | ReactNode | Slot for buttons/pills on the right. |
href / onClick | string / () => void | Make entire card interactive. |
titleAs | ElementType | Override rendered heading element (e.g., h3). |
Usage
<Card
title="Inventory batches"
actions={<Button buttonStyle="secondary">Open</Button>}
onClick={() => router.push('/admin/inventory')}
/>
Tips
- Cards inherit spacing from
index.scss; avoid extra padding wrappers unless necessary.
Collapsible (@payloadcms/ui/elements/Collapsible)
Role: Expandable section wrapper used inside array rows and grouped forms.
Import
import { Collapsible } from '@payloadcms/ui/elements/Collapsible'
Key props
| prop | type | notes |
|---|---|---|
header | ReactNode | Always-visible summary content. |
initCollapsed | boolean | Initial toggle state; defaults to collapsed. |
isCollapsed | boolean | Control state externally. |
onToggle | (collapsed: boolean) => void | Sync external state or analytics. |
collapsibleStyle | `'default' | 'error'` |
Usage
<Collapsible
className="array-field__row"
initCollapsed={false}
header={<span>{rowTitle}</span>}
>
{children}
</Collapsible>
Tips
- Combine with
dragHandlePropsfromDraggableSortableto make rows draggable while preserving toggles.
Drawer (@payloadcms/ui/elements/Drawer)
Role: Right-side overlay for nested editing (mirrors Payload relationship drawers).
Import
import { Drawer, DrawerToggler } from '@payloadcms/ui/elements/Drawer'
Key props
| prop | type | notes |
|---|---|---|
slug | string | Required unique identifier per drawer instance. |
title | string | Header text; shown next to close icon. |
Header | ReactNode | Replace the standard header entirely. |
gutter | boolean | Adds internal padding. |
Usage
<Drawer slug="product-selector" title="Select product" gutter>
<ProductList onSelect={handleSelect} />
</Drawer>
<DrawerToggler slug="product-selector">
<Button buttonStyle="secondary">Open drawer</Button>
</DrawerToggler>
Tips
- Wrap component file with
'use client'; drawers rely on window APIs. - Use
formatDrawerSlugwhen nesting drawers to avoid collisions.
Modal (@payloadcms/ui/elements/Modal)
Role: Faceless UI modal re-export for global overlays.
Import
import { Modal, useModal } from '@payloadcms/ui/elements/Modal'
Usage
const { toggleModal } = useModal()
<Modal slug="confirm-reset">
<div className="modal__content">
<h2>Reset filters?</h2>
<Button buttonStyle="primary" onClick={onConfirm}>Confirm</Button>
</div>
</Modal>
<Button onClick={() => toggleModal('confirm-reset', true)}>Reset filters</Button>
Tips
- Register modals once near the layout root to ensure portal context matches Payload’s admin shell.
ReactSelect (@payloadcms/ui/elements/ReactSelect)
Role: Styled react-select adapter used across select and relationship fields.
Import
import { ReactSelect, type Option } from '@payloadcms/ui/elements/ReactSelect'
Key props
| prop | type | notes |
|---|---|---|
options | `Option[] | OptionGroup[]` |
isMulti | boolean | Enable multi-value selection; returns Option[]. |
isCreatable | boolean | Allow creating ad-hoc options. |
customProps | CustomSelectProps | Hook into Payload’s document drawers for relationships. |
value | `Option | Option[]` |
Usage
<ReactSelect
options={products}
value={selectedProduct}
isSearchable
isClearable
onChange={(option) => setSelectedProduct(option as Option<number>)}
/>
Tips
- Pass
placeholderstrings orLabelFunctionto localize. - For full relationship behavior (create/edit drawers), prefer the Relationship field wrapper.
DatePickerField (@payloadcms/ui/elements/DatePicker)
Role: Calendar and time input matching Payload’s date fields.
Import
import { DatePickerField } from '@payloadcms/ui/elements/DatePicker'
Key props
| prop | type | notes |
|---|---|---|
value | `Date | string` |
onChange | (date: Date) => void | Emits JS Date objects. |
readOnly | boolean | Prevent user edits but keep styling. |
placeholder | string | Ghost text when empty. |
| Day/Time picker props | Inherits from Payload’s DayPickerProps and TimePickerProps. |
Usage
<DatePickerField
value={row.receivedDate}
onChange={(date) => updateDate(format(date))}
placeholder="Select received date"
/>
Tips
- Combine with
DateTimeFieldwhen you need server-managed validation and localization.
DraggableSortable (@payloadcms/ui/elements/DraggableSortable)
Role: Drag-and-drop wrapper for reorderable lists tied to @dnd-kit.
Import
import { DraggableSortable } from '@payloadcms/ui/elements/DraggableSortable'
Key props
| prop | type | notes |
|---|---|---|
ids | string[] | Array of unique IDs matching child order. |
onDragEnd | ({ moveFromIndex, moveToIndex }) => void | Required reorder logic. |
onDragStart | ({ id }) => void | Optional analytics/feedback. |
className | string | Apply Payload spacing helpers (array-field__draggable-rows). |
Usage
<DraggableSortable
ids={rows.map((row) => row.id)}
className="array-field__draggable-rows"
onDragEnd={({ moveFromIndex, moveToIndex }) => reorderRows(moveFromIndex, moveToIndex)}
>
{rows.map(renderRow)}
</DraggableSortable>
Tips
- Children should render
data-idattributes via theDraggableSortableitem helpers (see existing array field source) for smooth dragging.
Table (@payloadcms/ui/elements/Table)
Role: Minimal data table for list-style summaries.
Import
import { Table } from '@payloadcms/ui/elements/Table'
Key props
| prop | type | notes |
|---|---|---|
columns | Column[] | Use Payload’s column definition shape (accessor, Header, etc.). |
data | Record<string, unknown>[] | Array of row objects keyed by column accessor. |
appearance | `'default' | 'condensed'` |
BeforeTable | ReactNode | Render filters/action bars above the table. |
Usage
<Table
appearance="condensed"
columns={columns}
data={rows}
/>
Tips
- For orderable tables, use the companion
OrderableTableexport in the same folder.
Tooltip (@payloadcms/ui/elements/Tooltip)
Role: Hover/focus tooltip used for icon buttons and status pills.
Import
import { Tooltip } from '@payloadcms/ui/elements/Tooltip'
Key props
| prop | type | notes |
|---|---|---|
show | boolean | Control visibility manually; defaults to hover trigger. |
delay | number | Milliseconds before showing. |
position | `'top' | 'bottom'` |
alignCaret | `'left' | 'center' |
Usage
<Tooltip position="top" delay={150}>
<Button buttonStyle="icon-label" icon="info" aria-label="More info" />
</Tooltip>
Tips
- Wrap only the trigger element; Tooltip clones its child and wires up events.
Field Primitives
FieldLabel (@payloadcms/ui/fields/FieldLabel)
Role: Standardized label element with required indicator support.
Import
import { FieldLabel } from '@payloadcms/ui/fields/FieldLabel'
Usage
<FieldLabel
htmlFor="bulkRows"
label="Bulk inventory batches"
/>
Notes
- Accepts Payload’s
GenericLabelProps, includinglocalizedandrequiredflags. - Pair with
FieldDescriptionfor helper text.
FieldDescription (@payloadcms/ui/fields/FieldDescription)
Role: Helper text block with consistent spacing and subdued color.
Import
import { FieldDescription } from '@payloadcms/ui/fields/FieldDescription'
Usage
<FieldDescription
path="bulkRows"
description="Add one row per product variant."
/>
Notes
- The
pathis used by Payload tooling for error linking; keep it stable.
FieldError (@payloadcms/ui/fields/FieldError)
Role: Inline error message styled to match Payload validations.
Import
import { FieldError } from '@payloadcms/ui/fields/FieldError'
Usage
<FieldError
message="Quantity must be greater than zero"
/>
Notes
- Render conditionally when
showErrorflags trigger within field components.
TextInput & TextField (@payloadcms/ui/fields/Text)
Role: Single-line input primitive and full field wrapper tied to form state.
Import
import { TextInput } from '@payloadcms/ui/fields/Text'
Key props
| prop | type | notes |
|---|---|---|
path | string | Required unique path for Payload tracking. |
value | string | Controlled input value. |
onChange | (event) => void | Standard change handler (or ReactSelect change when hasMany). |
AfterInput / BeforeInput | ReactNode | Slots for adornments. |
localized | boolean | Adjusts layout when translating. |
placeholder | `string | Record<string, string>` |
Usage (controlled input)
<TextInput
path={`${row.id}-totalStock`}
value={row.totalStock ?? ''}
onChange={(event) => updateRow(row.id, event.target.value)}
placeholder="Enter quantity"
required
/>
Tips
- When building full custom fields, use
useFieldto sync values with Payload and pass thepathconsistently.
Textarea (@payloadcms/ui/fields/Textarea)
Role: Multi-line text area with Payload typography.
Import
import { TextareaInput } from '@payloadcms/ui/fields/Textarea'
Key props
| prop | type | notes |
|---|---|---|
rows | number | Default row count; expand with CSS if needed. |
value | string | Controlled text. |
onChange | (ChangeEvent<HTMLTextAreaElement>) => void | Update state. |
Usage
<TextareaInput
path="notes"
value={notes}
onChange={(event) => setNotes(event.target.value)}
placeholder="Optional notes"
/>
Select (@payloadcms/ui/fields/Select)
Role: Payload-managed select field leveraging ReactSelect styles.
Import
import { SelectInput } from '@payloadcms/ui/fields/Select'
Key props
| prop | type | notes |
|---|---|---|
options | OptionObject[] | Usually from collection config. |
hasMany | boolean | Enables multi-select; returns string[]. |
isSortable | boolean | Exposes drag handles for multi values. |
placeholder | `LabelFunction | string` |
Usage
<SelectInput
path="deliveryDate"
name="deliveryDate"
options={dateOptions}
value={currentDateId}
onChange={(option) => setCurrentDate(option?.value)}
/>
Relationship (@payloadcms/ui/fields/Relationship)
Role: Fetch-on-demand relation picker with optional drawer editing.
Import
import { RelationshipField } from '@payloadcms/ui/fields/Relationship'
Key props
| prop | type | notes |
|---|---|---|
relationTo | string[] | Collection slugs supported (mono or poly). |
appearance | `'select' | 'drawer'` |
allowCreate / allowEdit | boolean | Enables “Create new” and “Edit” buttons. |
hasMany | boolean | Multi-relation mode; returns arrays. |
filterOptions | FilterOptionsResult | Pre-filter server results. |
Usage
<RelationshipField
path="product"
field={fieldConfig}
relationTo={['products']}
hasMany={false}
allowEdit
allowCreate
value={currentProduct}
onChange={setCurrentProduct}
/>
Tips
- Use
maxResultsPerRequestto balance performance when large collections exist.
DateTime (@payloadcms/ui/fields/DateTime)
Role: Full Payload date field wrapper including timezone + validation.
Import
import { DateTimeField } from '@payloadcms/ui/fields/DateTime'
Usage
<DateTimeField
path="receivedDate"
field={fieldConfig}
value={valueFromForm}
onChange={setValue}
/>
Notes
- Automatically wires
DatePickerField; rely on it when you need Payload’s default min/max validation and timezone handling baked in.
Checkbox (@payloadcms/ui/fields/Checkbox)
Role: Styled checkbox with tri-state support.
Import
import { CheckboxField } from '@payloadcms/ui/fields/Checkbox'
Key props
| prop | type | notes |
|---|---|---|
checked | boolean | Controlled value. |
partialChecked | boolean | Show indeterminate state (e.g., bulk toggles). |
onChange | (value: boolean) => void | Emit selection state. |
Usage
<CheckboxField
path="confirm"
checked={isConfirmed}
onChange={setConfirmed}
field={fieldConfig}
/>
Array (@payloadcms/ui/fields/Array)
Role: Native array field wrapper with add/remove controls and draggable rows.
Import
import { ArrayField } from '@payloadcms/ui/fields/Array'
Usage
<ArrayField
path="bulkRows"
field={fieldConfig}
value={valueFromForm}
validate={fieldConfig.validate}
/>
Notes
- Combine with
DraggableSortableclasses (array-field,array-field__header,array-field__draggable-rows) when creating bespoke layouts that still resemble core arrays.
Blocks (@payloadcms/ui/fields/Blocks)
Role: Stackable content blocks with drawer-based block chooser.
Import
import { BlocksField } from '@payloadcms/ui/fields/Blocks'
Usage
<BlocksField
path="contentBlocks"
field={fieldConfig}
/>
Notes
- Components such as
BlocksDrawerandBlockRowlive in the same folder if you need deeper customization.
Upload (@payloadcms/ui/fields/Upload)
Role: File upload picker with thumbnail preview, relationship drawer, and server-driven validation.
Import
import { UploadField } from '@payloadcms/ui/fields/Upload'
Key props
| prop | type | notes |
|---|---|---|
field | UploadFieldClient | Use the config passed into custom components. |
path | string | Unique identifier for form state. |
onChange | Provided via Payload; typically not replaced manually. |
Usage
<UploadField
path="galleryHero"
field={fieldConfig}
/>
Tips
- Access the exported
UploadInputdirectly for lightweight file pickers without the full field chrome.
Patterns & Best Practices
- Sync with
useField: For bespoke components, callconst { value, setValue, showError } = useField({ path })and passshowErrorto inputs that support it. - Respect
path: Payload’s form state, localization, and validation rely on consistentpathstrings; do not reuse them across siblings. - Leverage CSS utilities: Copy existing class names (
pill,gutter--left,toolbar, etc.) from.scssfiles to inherit spacing without bespoke CSS. - Accessibility: All elements supply ARIA hooks. Keep
aria-label/htmlFor/aria-describedbyattributes wired when wrapping components. - Live updates: When upgrading Payload, re-run
pnpm installand diffnode_modules/@payloadcms/ui/distto spot new components or prop changes to mirror here.
📚 Comprehensive Payload CMS Guides
Detailed Payload guides with field configuration examples, custom components, and workflow optimization tips to speed up your CMS development process.
Frequently Asked Questions
Comments
No comments yet
Be the first to share your thoughts on this post!


