Payload CMS Admin UI Components: Complete Glossary

Authoritative reference for @payloadcms/ui elements & fields (v3.6+). Props, imports, usage examples, and best…

·Matija Žiberna·
Payload CMS Admin UI Components: Complete Glossary

📚 Comprehensive Payload CMS Guides

Detailed Payload guides with field configuration examples, custom components, and workflow optimization tips to speed up your CMS development process.

No spam. Unsubscribe anytime.

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.5+ Payload projects using the Next.js App Router in src/app with 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/* and dist/fields/* for .d.ts files that declare props, default behaviors, and helper exports.
  • Source inspection: Many components re-export JSX from nearby index.js files—quickly open them to confirm transitions, context requirements, or composed children.
  • CSS classes: Each folder ships a matching .scss file. 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.tsx shows 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 useField come 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

proptypenotes
buttonStyle`'primary''secondary'
size`'xsmall''small'
icon`'chevron''edit'
iconPosition`'left''right'`
programmaticSubmitbooleanForces form submission for detached buttons.
secondaryActions`secondaryActionsecondaryAction[]`

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 tooltip prop 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

proptypenotes
titlestringRequired heading text.
actionsReactNodeSlot for buttons/pills on the right.
href / onClickstring / () => voidMake entire card interactive.
titleAsElementTypeOverride 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

proptypenotes
headerReactNodeAlways-visible summary content.
initCollapsedbooleanInitial toggle state; defaults to collapsed.
isCollapsedbooleanControl state externally.
onToggle(collapsed: boolean) => voidSync external state or analytics.
collapsibleStyle`'default''error'`

Usage

<Collapsible
  className="array-field__row"
  initCollapsed={false}
  header={<span>{rowTitle}</span>}
>
  {children}
</Collapsible>

Tips

  • Combine with dragHandleProps from DraggableSortable to 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

proptypenotes
slugstringRequired unique identifier per drawer instance.
titlestringHeader text; shown next to close icon.
HeaderReactNodeReplace the standard header entirely.
gutterbooleanAdds 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 formatDrawerSlug when nesting drawers to avoid collisions.

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

proptypenotes
options`Option[]OptionGroup[]`
isMultibooleanEnable multi-value selection; returns Option[].
isCreatablebooleanAllow creating ad-hoc options.
customPropsCustomSelectPropsHook into Payload’s document drawers for relationships.
value`OptionOption[]`

Usage

<ReactSelect
  options={products}
  value={selectedProduct}
  isSearchable
  isClearable
  onChange={(option) => setSelectedProduct(option as Option<number>)}
/>

Tips

  • Pass placeholder strings or LabelFunction to 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

proptypenotes
value`Datestring`
onChange(date: Date) => voidEmits JS Date objects.
readOnlybooleanPrevent user edits but keep styling.
placeholderstringGhost text when empty.
Day/Time picker propsInherits from Payload’s DayPickerProps and TimePickerProps.

Usage

<DatePickerField
  value={row.receivedDate}
  onChange={(date) => updateDate(format(date))}
  placeholder="Select received date"
/>

Tips

  • Combine with DateTimeField when 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

proptypenotes
idsstring[]Array of unique IDs matching child order.
onDragEnd({ moveFromIndex, moveToIndex }) => voidRequired reorder logic.
onDragStart({ id }) => voidOptional analytics/feedback.
classNamestringApply 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-id attributes via the DraggableSortable item 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

proptypenotes
columnsColumn[]Use Payload’s column definition shape (accessor, Header, etc.).
dataRecord<string, unknown>[]Array of row objects keyed by column accessor.
appearance`'default''condensed'`
BeforeTableReactNodeRender filters/action bars above the table.

Usage

<Table
  appearance="condensed"
  columns={columns}
  data={rows}
/>

Tips

  • For orderable tables, use the companion OrderableTable export 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

proptypenotes
showbooleanControl visibility manually; defaults to hover trigger.
delaynumberMilliseconds 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, including localized and required flags.
  • Pair with FieldDescription for 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 path is 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 showError flags 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

proptypenotes
pathstringRequired unique path for Payload tracking.
valuestringControlled input value.
onChange(event) => voidStandard change handler (or ReactSelect change when hasMany).
AfterInput / BeforeInputReactNodeSlots for adornments.
localizedbooleanAdjusts layout when translating.
placeholder`stringRecord<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 useField to sync values with Payload and pass the path consistently.

Textarea (@payloadcms/ui/fields/Textarea)

Role: Multi-line text area with Payload typography.

Import

import { TextareaInput } from '@payloadcms/ui/fields/Textarea'

Key props

proptypenotes
rowsnumberDefault row count; expand with CSS if needed.
valuestringControlled text.
onChange(ChangeEvent<HTMLTextAreaElement>) => voidUpdate 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

proptypenotes
optionsOptionObject[]Usually from collection config.
hasManybooleanEnables multi-select; returns string[].
isSortablebooleanExposes drag handles for multi values.
placeholder`LabelFunctionstring`

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

proptypenotes
relationTostring[]Collection slugs supported (mono or poly).
appearance`'select''drawer'`
allowCreate / allowEditbooleanEnables “Create new” and “Edit” buttons.
hasManybooleanMulti-relation mode; returns arrays.
filterOptionsFilterOptionsResultPre-filter server results.

Usage

<RelationshipField
  path="product"
  field={fieldConfig}
  relationTo={['products']}
  hasMany={false}
  allowEdit
  allowCreate
  value={currentProduct}
  onChange={setCurrentProduct}
/>

Tips

  • Use maxResultsPerRequest to 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

proptypenotes
checkedbooleanControlled value.
partialCheckedbooleanShow indeterminate state (e.g., bulk toggles).
onChange(value: boolean) => voidEmit 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 DraggableSortable classes (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 BlocksDrawer and BlockRow live 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

proptypenotes
fieldUploadFieldClientUse the config passed into custom components.
pathstringUnique identifier for form state.
onChangeProvided via Payload; typically not replaced manually.

Usage

<UploadField
  path="galleryHero"
  field={fieldConfig}
/>

Tips

  • Access the exported UploadInput directly for lightweight file pickers without the full field chrome.

Patterns & Best Practices

  • Sync with useField: For bespoke components, call const { value, setValue, showError } = useField({ path }) and pass showError to inputs that support it.
  • Respect path: Payload’s form state, localization, and validation rely on consistent path strings; do not reuse them across siblings.
  • Leverage CSS utilities: Copy existing class names (pill, gutter--left, toolbar, etc.) from .scss files to inherit spacing without bespoke CSS.
  • Accessibility: All elements supply ARIA hooks. Keep aria-label/htmlFor/aria-describedby attributes wired when wrapping components.
  • Live updates: When upgrading Payload, re-run pnpm install and diff node_modules/@payloadcms/ui/dist to spot new components or prop changes to mirror here.
0

Frequently Asked Questions

Comments

Leave a Comment

Your email will not be published

10-2000 characters

• Comments are automatically approved and will appear immediately

• Your name and email will be saved for future comments

• Be respectful and constructive in your feedback

• No spam, self-promotion, or off-topic content

Matija Žiberna
Matija Žiberna
Full-stack developer, co-founder

I'm Matija Žiberna, a self-taught full-stack developer and co-founder passionate about building products, writing clean code, and figuring out how to turn ideas into businesses. I write about web development with Next.js, lessons from entrepreneurship, and the journey of learning by doing. My goal is to provide value through code—whether it's through tools, content, or real-world software.