# Display hints (/catalog/display-hints)

How a type says what names an item, where its text is, whether that text can name it and which icon it shows, how Marfa names an item from them, and the icon the owner chooses.



A type's `display_hints` tell an app how to show its items: the field that names an item, the field that holds its text, whether that text can name it, and an icon. [Type rules](/catalog/type-rules) has the rest of what a type you register must meet, and [Define a type](/build/define-a-type) shows how to set them.

## The hints [#the-hints]

`display_hints` takes four optional hints:

| Hint | What it holds | Marfa refuses |
| - | - | - |
| `title_field` | The name of the field that names an item. | A field the type and its ancestors don't declare, or a `thumbnail` field. |
| `body_field` | The name of the field that holds the item's text, **in Markdown**. Apps render it, and a device makes [edges](/catalog/edges) from its links. | The same as `title_field`. |
| `name_from_body` | `false` where the item's text never names it, however short, as on `core.highlight`, whose passage is its text but never its name. Unset, the text can name an item. | Anything but `true` or `false`. |
| `icon` | An [Iconify](https://iconify.design/) icon ID, `<set>:<name>`, from the `lucide` set (`@iconify-json/lucide` 1.2.149) or, for brand marks, the `simple-icons` set (`@iconify-json/simple-icons` 1.2.101), such as `lucide:star` or `simple-icons:github`. | A bare name such as `star`, another set, a name the set's version lacks, an alias such as `lucide:alert-circle`, an icon the set marks hidden, or a wrong-case or padded ID. |

Marfa refuses a hint with `400 invalid_schema`, naming the member, such as `display_hints.icon`.

**Marfa doesn't check the text in `body_field`.** It stores the value as sent and never refuses it as malformed Markdown, so a [connector](/build/connector-pull) converts a vendor's HTML first, or an app shows the tags.

**The icon sets are fixed because apps carry their own copy**, so an icon draws offline and looks the same in every app. The accepted IDs are in [`icon-set-lucide.json`](https://github.com/withmarfa/marfa/blob/main/packages/types/generated/icon-set-lucide.json) and [`icon-set-simple-icons.json`](https://github.com/withmarfa/marfa/blob/main/packages/types/generated/icon-set-simple-icons.json).

**Each hint comes from the nearest type that sets it**, so a type that sets only an `icon` keeps the title and body its parent names. `GET /types/{id}` answers each hint after inheritance, and `GET /types` lists only the hints each type sets itself.

## Names and previews [#names-and-previews]

The server and a device name an item by one rule, so they show the same name, offline included.

* **The name** comes from the first of these fields that holds text: `title_field`, `title`, `name`, `body_field`, `body`, `text`, `filename`, `url` and `address`, leaving out `body_field`, `body` and `text` where `name_from_body` is `false`. Marfa takes the first line, collapses each run of whitespace and keeps at most 120 characters, ending in `…` where it cuts.
* **A name taken from `body_field`, `body` or `text` loses its Markdown**, so a note whose body starts `# Plan` is named `Plan`. A name from any other field keeps every character.
* **A part or an excerpt with no title of its own is named after the item it belongs to**, by the [edge's](/catalog/edges) label and that item's name: a comment is "Comment on Plan" and a highlight "Excerpt from Thinking, Fast and Slow". Several highlights can share a name. Where it has more than one such item, the oldest edge to one out of the bin that the reader may read names it, and with none, its own fields do.
* **An item with no name** is `Untitled` to the server. A device answers that it has none, so each app chooses its own word.
* **A preview** is the body field's text without its Markdown, at most 240 characters. Where the name came from the body field, the preview leaves out that line and every line before it. Only a device makes one.

A Swift app reads both with [`displays(of:)`](/swift-sdk/items#names-and-previews).

## The owner's icon [#the-owners-icon]

**The owner can choose the icon of any type**, a shipped or connector type included, without replacing it. The choice sits beside the type's definition, so the author's icon stays the default. [Set a type's icon](/api-reference/types/setTypeIcon) and [clear a type's icon](/api-reference/types/clearTypeIcon) are the operations:

```bash
marfa types set-icon user.recipe lucide:chef-hat
marfa types clear-icon user.recipe
```

* **Reads answer it in place of the author's icon**, and a subtype with no icon of its own shows it.
* **Replacing the type keeps it, and deleting the type discards it.** A type registered again under the same identifier starts without one.
* **Devices take it at their next catch-up**, or when a follow next opens its stream. No event announces it.
* **The icon follows the same rules as the author's.** One the sets don't hold is refused `400 invalid_schema`, naming `icon`, and a type nothing registered is refused `404 type_not_found`. A refused call leaves the icon the type had.
* **Who can change it:** the owner, a local process, or a key with `schema.write` and write on the type. A key without `schema.write` is refused `403 forbidden`, and one without write on the type `403 type_not_permitted`.

[Change a type](/build/change-a-type) explains what a replacement does with the owner's icon when you send back what a `GET` answered.

The rules behind this page are in the [types](https://github.com/withmarfa/marfa/blob/main/conformance/spec/types.md) and [device](https://github.com/withmarfa/marfa/blob/main/conformance/spec/device.md) chapters of the contract.
