---
title: "Field patterns"
description: "Theme and background fields, conditional fields, link fields, reused fields and block images."
requested_language: nl
language: en
translation_notice: "This page isn't translated yet"
url: https://docs.systhema.app/nl/payload/editor/field-patterns
version: unreleased (main)
docs_index: https://docs.systhema.app/nl/llms.txt
---
> This page isn't translated yet. Showing English.


These patterns recur in Systhema's own blocks. Reuse them in your custom blocks and templates so editors meet the same controls everywhere.

## Theme + background fields

```ts
import { getFirstKey, getTokens, toTitleCase } from '@systhemaui/core'

const { colorSystem } = getTokens()
const colorSystemKeys = Object.keys(colorSystem || {})
const layoutBackgrounds = Object.keys(
  (colorSystem[getFirstKey(colorSystem) as string] as Record<string, Record<string, unknown>>)
    .layout?.bg || {},
)

const themeField = {
  name: 'theme',
  type: 'select',
  options: colorSystemKeys.map((k) => ({ label: toTitleCase(k), value: k })),
  defaultValue: colorSystemKeys[0],
}

const layoutBgField = {
  name: 'layoutBg',
  type: 'select',
  options: layoutBackgrounds.map((k) => ({ label: toTitleCase(k), value: k })),
  defaultValue: layoutBackgrounds[0],
}
```

## Conditional fields

```ts
{ name: 'url', type: 'text', admin: { condition: (_, s) => s?.linkType === 'custom' } }
{ name: 'reference', type: 'relationship', relationTo: 'pages',
  admin: { condition: (_, s) => s?.linkType === 'internal' } }
```

## Link fields

`linkFields()` (from `@systhemaui/payload/fields`) is the `linkType` / `url` / `reference` / `newTab` set the built-in button, chip, icon, card, image, video and column-item blocks are built from, with the same translated labels, conditions and defaults. Spread it into any block or template field list:

```ts
import { linkFields } from '@systhemaui/payload/fields'

fields: [
  { name: 'title', type: 'text' },
  ...linkFields(), // None / Custom URL / Internal link, "None" preselected
  // ...linkFields({ allowNone: false })                   — always links (a button)
  // ...linkFields({ relationTo: ['pages', 'posts'] })     — polymorphic target
  // ...linkFields({ newTab: false })                       — no "open in new tab" box
  // ...linkFields({ newTabNeedsTarget: true })             — "open in new tab" only once a URL/page is set
  // ...linkFields({ condition: (s) => s?.layout === 'card' }) — every link field gated on a sibling value
  // ...linkFields({ description: 'Makes the whole card clickable' }) — help text under the link type
]
```

Render it with the same helper the blocks use: `linkType === 'custom' ? url : localizedInternalRefToHref(reference, locale)` (`internalRefToHref` / `localizedInternalRefToHref` resolve a populated `reference` to its href, homepage-aware).

## Reusing block fields

```ts
import { ButtonBlockFields } from '@systhemaui/payload/blocks'

fields: [{ name: 'title', type: 'text' }, ...ButtonBlockFields]
```

## Block images (editor preview)

A block carries two images and they are different sizes. Payload draws `admin.images.icon` at 20x20 in the Lexical slash menu and toolbar, and `admin.images.thumbnail` in a 3:2 `object-fit: cover` box in the block picker and the Blocks-field selector. Draw them separately. A 20px glyph scaled up to picker size is a blur.

Systhema's own thumbnails are 480x320 wireframes in `utils/blockThumbnails.ts`, one per built-in block.

```ts
import { encodedSvg } from '@systhemaui/payload/utils/svg'
import { blockThumbnail } from '@systhemaui/payload/utils/blockThumbnails'

admin: {
  images: {
    icon: encodedSvg({ name: 'lexical-block-section', hexIdentifier: 'b5b5b5' }),
    thumbnail: { url: blockThumbnail('section'), alt: 'Section block preview' },
  },
}
```

Either slot also takes a bare URL string instead of the `{ url, alt }` object. Payload deprecated the older top-level `imageURL` and `imageAltText` in favour of `admin.images`.
