---
title: "Custom text states"
description: "Inline styles editors can apply, and how they render."
url: https://docs.systhema.app/next/payload/editor/text-states
version: unreleased (main)
docs_index: https://docs.systhema.app/next/llms.txt
---

For richer formatting (e.g. semantic colors that map to design-token values), register custom text states:

```ts
const userSysthemaConfig: SysthemaPayloadPluginOptions = {
  customTextStates: [
    {
      editor: ['root', 'region'],
      state: {
        color: {
          highlight: {
            label: 'Highlight',
            css: {
              backgroundColor: 'var(--color-highlight)',
              color: 'var(--color-highlight-text)',
            },
          },
        },
      },
    },
  ],
}
```

## A text state is an inline style

`css` is applied as an **inline `style` attribute** — in the editor and on the rendered page alike. That is what lets it hold anything, and it is also the one rule to keep in mind: the values are substituted **on the element the state sits on**.

Naming a token directly, as above, works in both places. Referencing a variable of **your own** does not, unless you declare it in the right scope:

```css
/* your admin stylesheet */
:root {
  --brand-gradient: linear-gradient(135deg, var(--color-brand-a), var(--color-brand-b));
}
```

```ts
css: {
  backgroundImage: 'var(--brand-gradient)'
}
```

That renders correctly on the public site and **resolves to nothing in the admin**. A `var()` inside a custom property is substituted where the property is **declared**, not where it is used — and in the Payload Admin the Systhema tokens are declared on the editor root, not on `:root`. So `--brand-gradient` looks up colors that do not exist in its scope, becomes invalid, and every element using it gets no value at all. There is no error and no warning; a state that pairs `background-image` with `-webkit-text-fill-color: transparent` renders as **invisible text**.

Declare the variable on the editor's own scope instead, which Systhema publishes as **`.systhema-editor-tokens`**:

```css
/* your admin stylesheet — Payload's `admin.css` */
.systhema-editor-tokens {
  --brand-gradient: linear-gradient(135deg, var(--color-brand-a), var(--color-brand-b));
}
```

Systhema stamps that class onto every editor built from a tier factory — `rootLexicalEditor`, `regionLexicalEditor`, `fragmentLexicalEditor`, `slotLexicalEditor`, which are exactly the tiers a text state can target — using Lexical's own root-element API rather than a class name. Target it instead of Payload's internal `.ContentEditable__root`: that class is an implementation detail of `@payloadcms/richtext-lexical`, and if it is renamed your admin CSS stops resolving with nothing to point at the cause. The class name is also exported as `SYSTHEMA_EDITOR_TOKENS_CLASS` from `@systhemaui/payload`, for CSS you generate rather than write. A field built with a bare `lexicalEditor()` carries no Systhema feature and so no stamp — it still gets the tokens through Payload's own class, just not the owned one.

> [!WARNING]
> **Using `optimization.obfuscateVariables`?** These `var(--…)` names end up as inline styles **stored in the database** and rendered into markup, which puts them outside the stylesheet the obfuscator rewrites. A variable renamed to `--sa` leaves the inline `var(--color-highlight)` resolving to nothing — the text silently renders unstyled, with a green build.
>
> Every variable name you reference from a text state (or any other CMS-authored inline style) must be kept literal:
>
> ```ts title="systhema.config.ts"
> optimization: {
>   obfuscateVariables: { ignore: ['--color-highlight', '--color-highlight-text'] },
>   // or a whole family: ignore: ['--color-']
> }
> ```
>
> The post-build `systhema-core obfuscate` pass repairs the references it can see in the build output and warns loudly about the rest — but content published after the build re-renders the original name, so `ignore` is the only durable fix. See [`optimization`](https://docs.systhema.app/next/styling/optimization.md#obfuscation).
