---
title: "Document types"
description: "Document types: the Writing Room plugin for Sanity Studio."
canonical_url: https://writingroom.studio/docs/document-types/
plugin_version: 0.3.0
license: MIT
---

# Document types

The room writes Posts by default. To write other kinds too, list their document types:

```ts
writingRoom({
  types: ['post', 'caseStudy'],
})
```

### Fields

The room reads each type's schema to find what it writes:

| | It looks for | If there's none |
|---|---|---|
| Title | `title`, else the field the type's preview shows as its title, else the first string field | The type is left out |
| Body | `body`, else `content`, else the first portable text field | The type is left out |
| Slug | `slug`, else the first slug field | No slug is settled on publish |
| Published date | `publishedAt`, else the first date field whose name contains "publish" | No date is stamped on publish |
| Cover image | `coverImage`, else `mainImage`, else the first image field | No "Add a cover image" nudge after a publish |

If it guesses wrong, name the field: `{type: 'article', fields: {body: 'content', title: 'headline'}}`. Every other field (excerpt, tags, a client name…) shows up under **Details**, with nothing to configure.

### Details

**Details** in the room's controls swaps the body for the document's other fields, on one page in the order your schema gives them. The title stays where it is, and the arrow or Esc goes back to the writing.

- **Simple fields get the room's own inputs**: strings, text, numbers, booleans, dates, slugs and tag lists.
- **Everything else is Sanity's own input**, looking as it does in the rest of your Studio: references, images, files, arrays of objects, and lists of choices. With the [matching theme](https://writingroom.studio/docs/look-and-feel.md#a-matching-studio-theme-optional) they sit closer to the room's look.
- **Your custom inputs are used as they are.** A field with its own `components.input` or `components.field` is never replaced.
- **List the Writing Room last in `plugins` if another plugin wraps every input.** For simple fields the room's inputs take the place of Sanity's, which ends Sanity's chain of input components there. A plugin listed before the Writing Room still wraps the room's inputs in Details; one listed after it, and a `form.components.input` in your own Studio config, does not. Everything still appears in the Structure form.
- **Your schema's rules apply**: `hidden`, `readOnly` and validation behave as they do in the standard form. Field groups are not shown as tabs; fieldsets are kept.
- A type with only a title and a body has no Details button.

Details are saved as you type, like the writing. If a required field blocks a publish, the room opens Details at that field.

If the Details view can't be shown in your Studio, the room says so and offers **Open in Structure** instead.

### The body

The editor is built from the body field's own type, so the room only offers what that type can store. A `blockContent` with headings, quotes, bullets, links and images gets exactly those: no code blocks, embeds or numbered lists in the Insert Menu, selection bubble or markdown shortcuts. Image description and caption inputs appear only when your image type has `alt` and `caption` fields.

To offer the room's own blocks (YouTube/Vimeo/Spotify embeds, code blocks, section breaks), add them to your body type. The plugin registers them for you, under prefixed names that can't clash with yours:

```ts
import {writingRoomBlocks} from 'sanity-plugin-writing-room'

defineType({
  name: 'blockContent',
  type: 'array',
  of: [{type: 'block'}, {type: 'image'}, ...writingRoomBlocks],
})
```

Your site then renders them as `writingRoomEmbed`, `writingRoomCodeBlock` and `writingRoomSectionBreak`. (The starter `writingRoomSchemaTypes` uses the original names, `embed`, `codeBlock` and `sectionBreak`; the room handles both.)

Blocks of your own that the room doesn't know (a `callout`, a product card…) keep their place in the text as a quiet placeholder: the Writer can move or delete them, and **Edit in Structure** opens that block in the standard form.

### Labels and URLs

The Lobby's **New** button starts a document of your type ("New Post"); with several types it asks which. Recent writing lists them together. The room names each type with its schema `title` ("Case Study"). If a name comes out wrong, set it yourself:

```ts
writingRoom({
  types: ['post', {type: 'news', title: 'News', pluralTitle: 'News'}],
})
```

| Option | Default | What it does |
|---|---|---|
| `types` | `['post']` | The document types the room writes, as names or `{type, title?, pluralTitle?, fields?}`. |
| `types[].title` | the schema type's `title` | What one is called: "New Case Study". |
| `types[].pluralTitle` | `title` made plural | What several are called: "Case Studies". |
| `types[].fields` | detected | `{title?, body?, slug?, publishedAt?, image?}`: field names, when the room guesses wrong. |

The first type is the default: its documents open at `/writing-room/<id>`, the others at `/writing-room/<type>/<id>`. A Studio with one type keeps short URLs, and links to it keep working if you add more types later, as long as it stays first.

If a type in `types` isn't in your schema, or has no title or body the room can find, the room leaves it out and says why in the browser console. Slugs are unique within a type, so a Post and a Case Study can both be `hello-world`.

---

Writing Room is MIT licensed and free, made by [Zephyr Pixels](https://zephyrpixels.dev). Bugs and questions go to [GitHub issues](https://github.com/mematthew123/sanity-plugin-writing-room/issues). More: [About](https://writingroom.studio/about.md), [Contact](https://writingroom.studio/contact.md), [Privacy](https://writingroom.studio/privacy.md).

Every page of this site as markdown: [https://writingroom.studio/llms.txt](https://writingroom.studio/llms.txt)
