> From the [Strife developer docs](https://strife.app/docs/reference/field-reference/fields.html). Every page is listed in [llms.txt](https://strife.app/docs/llms.txt).

# fields.html()

Rich-text (HTML) editor with configurable formatting/content availability, plus selectable image, callout, and custom-component presets.

Rich-text input. Maps to editor `{ name: 'str-textarea', type: 'html' }`. Output is HTML-as-string — markup is stored verbatim; sanitization happens at render time (server-side renderers / SDKs), not at write time.

## Example

```ts
fields.html({
  label: 'Body',
  localizable: true,
  marks: ['bold', 'italic', 'link'],
  nodes: [
    'heading2',
    'bulletList',
    {
      type: 'image',
      sizes: [
        { label: 'Wide', width: 1200, height: 630, default: true },
        { label: 'Square', width: 800, height: 800 },
      ],
      styles: [
        { label: 'Drop shadow', group: 'Effects', cssClass: 'shadow', imgproxyParams: ['sh:0.5'] },
      ],
      quality: [{ label: 'High', quality: 90 }],
    },
  ],
})
```

## Options

| Option           | Type                                                          | Required | Description                                                                                                         |
| ---------------- | ------------------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------- |
| `label`          | `string`                                                      | Yes      | Label shown to editors in Strife Studio.                                                                            |
| `description`    | `string`                                                      | No       | Tooltip shown to editors.                                                                                           |
| `localizable`    | `boolean`                                                     | No       | When `true`, output is `Record<string, string>` instead of `string`.                                                |
| `searchable`     | `boolean`                                                     | No       | Include in the team's search index.                                                                                 |
| `filterable`     | `boolean`                                                     | No       | Allow filtering content lists by this value.                                                                        |
| `protected`      | `boolean`                                                     | No       | Restrict editing to users with the appropriate permission.                                                          |
| `propertyName`   | `string`                                                      | No       | Override the stored property name.                                                                                  |
| `placeholder`    | `string \| null`                                              | No       | Hint text shown when the editor is empty.                                                                           |
| `marks`          | `HtmlMark[]`                                                  | No       | Inline-formatting tools the editor offers.                                                                          |
| `nodes`          | `HtmlNode[]`                                                  | No       | Block-level content the editor offers. `image`, `callout`, and `customComponent` entries can carry their own configuration — see below. |
| `documentSchema` | `{ content?: string; placeholders?: Record<string, string> }` | No       | Forces a Tiptap content structure (e.g. `'heading paragraph+'`) and per-node-type placeholder text.                 |

`HtmlMark` is one of: `bold`, `italic`, `underline`, `strike`, `link`.

`HtmlNode` is either a bare `HtmlNodeName` — one of `paragraph`, `heading1`, `heading2`, `heading3`, `blockquote`, `bulletList`, `orderedList`, `checkList`, `codeBlock`, `image`, `video`, `table`, `details` — or a configured `image`/`callout`/`customComponent` object:

* **`{ type: 'image', sizes?, styles?, quality? }`** — presets offered in the image toolbar once an image is inserted. These are _selectable options_, not enforced constraints — contrast with [`fields.image()`](https://strife.app/docs/reference/field-reference/fields.image.md)'s mandatory `width`/`height`/`format`.
  * `sizes: { label, width, height, default? }[]` — selectable dimension presets. `height: 0` keeps the source aspect ratio; mark one entry `default: true` to auto-apply it when an image is inserted.
  * `styles: { label, group?, cssClass?, imgproxyParams? }[]` — selectable visual-style presets. `cssClass` lands on the rendered `<figure>`; `group` buckets the picker dropdown; `imgproxyParams` are server-side imgproxy processing operations.
  * `quality: { label, quality, imgproxyParams? }[]` — selectable compression presets (`quality` is 1–100).
* **`{ type: 'callout', variants: { label, value }[] }`** — the callout block's selectable class variants; multiple can be combined on one callout. A bare `'callout'` node name isn't valid on its own — without `variants` it would be a silent no-op, so it must always be given in this configured form. `label` is the picker label; `value` becomes the CSS class token on the rendered callout (compiles to wire `name`).
* **`{ type: 'customComponent', components: { tag, label, attributes? }[] }`** — customer web components the editor may insert (e.g. a form embed distributed as a custom element, `<lime-form form-id="...">`). Like `callout`, a bare `'customComponent'` node name isn't valid — without `components` it would be a silent no-op. Each entry: `tag` is the custom-element tag name; `label` is the insert-menu label.
  * `attributes: { name, label?, default? }[]` — what an author may fill in on each inserted instance. `name` is the HTML attribute written to the markup, `label` names the field in the editor (defaults to `name`), and `default` pre-fills it on insert. The placeholder renders one field per declared attribute, so a page with several of the same component gives each one its own `form-id` — and an author fills in a value, never attribute syntax.
  * Declare an attribute with no `default` to get an empty field. Leaving a field empty writes no attribute at all, rather than `name=""`.
  * The set is schema-owned: attributes you don't declare can't be added from the editor, and a component that declares none gets no editing affordance. Attributes already present on stored markup are preserved untouched whether or not the schema declares them.
  * `defaultAttrs: Record<string, string>` is the deprecated 0.11.0 spelling — `{ 'form-id': 'x' }` means the same as `[{ name: 'form-id', default: 'x' }]`, minus the field label. Existing schemas keep working; new ones should use `attributes`.

> [!WARNING]
> **Pilot-scoped today.** `tag` must be one of a small set of element names the editor's parse-time allowlist already recognizes (currently Kalmar Energi's Lime forms, `lime-form`/`simpli-form`) — any other tag is dropped like any other unmodeled markup, same as an unrecognized HTML element pasted into the editor. Recognized elements always render as a static placeholder in Strife Studio — the editor never mounts or hydrates the real element, and never loads the customer's script — the real component only renders where the published HTML is actually rendered, on the customer's own site (which must already have its loader script installed there). There is no Strife Studio UI for `customComponent` yet — `nodes` (or hand-edited template JSON) is currently the only way to set it, same as `quality` under `image` above.

> [!NOTE]
> Not every `nodes` entry produces a visible toolbar button today — `paragraph` and `table` have no corresponding control yet (they're accepted for forward-compatibility). Every `HtmlMark` value and every other `HtmlNodeName` value does show one.

> [!WARNING]
> **No Strife Studio UI for quality presets.** `sizes` and `styles` can also be authored by hand in Strife Studio's field settings (as "Image Presets" / "Style Presets" tables), but `quality` has no equivalent point-and-click control — `fields.html()`'s `nodes` (or hand-edited template JSON) is currently the only way to set it.

Alignment, alt text, and crop/zoom/pan on an inserted image are purely interactive per-image state set by the editor in Strife Studio — there's no schema-level way to default or constrain those.

## Output type

`string` (HTML), or `Record<string, string>` when `localizable: true`.

## See also

* [Rich Content](https://strife.app/docs/reference/fields/rich-content.md) — the same editor, documented from the Strife Studio UI side.
* [`fields.paragraph()`](https://strife.app/docs/reference/field-reference/fields.paragraph.md) — same underlying textarea component, but stores plain text instead of HTML.
