> ## Documentation Index
> Fetch the complete documentation index at: https://developers.reintersect.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Component catalog

> The closed set of components blocks are built from, what Reintersect decides for you, and what's deliberately left out.

> Reintersect apps are in developer preview. Names and limits can still change before general
> release.

Blocks are built from a fixed catalog of components. Reintersect draws each one with its own design
system, so blocks match the product in light and dark mode, at every width and on every surface.
Import components from `@reintersect/sdk/components`:

```tsx theme={null}
import {
  Actions,
  Block,
  Button,
  Header,
  MetaItem,
  MetaList,
  Status,
  Time,
} from "@reintersect/sdk/components";
```

Set `"jsx": "react-jsx"` and `"jsxImportSource": "@reintersect/sdk"` in your `tsconfig.json`. There
are no intrinsic elements: `<div>` and `<span>` are type errors. Your own function components may
return JSX or a `Promise` of JSX. To write components that return an `Effect`, set
`"jsxImportSource": "@reintersect/sdk/effect"` instead.

## Groups

<Columns cols={2}>
  <Card title="Frame" icon="frame" href="/components/frame">
    `Block`, `Header`, `Section`, `Footer`, `Divider`
  </Card>

  <Card title="Layout" icon="columns-3" href="/components/layout">
    `Stack`, `Row`, `Columns`, `Column`, `Callout`
  </Card>

  <Card title="Text" icon="type" href="/components/text">
    `Text`, `Heading`, `Prose`, `Code`, `Quote`, `Time`, `Duration`, `Icon` and rich text
  </Card>

  <Card title="Data" icon="table" href="/components/data">
    `Badge`, `Status`, `Person`, `MetaList`, `Facts`, `Metrics`, `Progress`, `AvatarStack`,
    `ItemList`, `Steps`, `Table`, `Chart`, `Image`, `File`, `Reference`
  </Card>

  <Card title="Interactive" icon="mouse-pointer-click" href="/components/interactive">
    `Button`, `Actions`, `Menu`, `ChoiceGroup`, `Form`, `Toggle`, `Select`, `TextInput`,
    `DateTimePicker`, `Tabs`
  </Card>

  <Card title="Recipes" icon="chef-hat" href="/recipes/overview">
    Ready-made blocks built from the catalog: approvals, polls, deployments, incidents and more.
  </Card>
</Columns>

## Every export

| Group | Components |
| - | - |
| Frame | `Block`, `Header`, `Section`, `Footer`, `Divider` |
| Layout | `Stack`, `Row`, `Columns`, `Column`, `Callout` |
| Text | `Text`, `Heading`, `Prose`, `Code`, `Quote`, `Time`, `Duration`, `Icon` |
| Rich text inside `Prose` and `Text` | `Paragraph`, `Bold`, `Italic`, `Strike`, `InlineCode`, `Link`, `Mention`, `Emoji`, `HardBreak`, `UnorderedList`, `OrderedList`, `ListItem`, `Blockquote` |
| Data | `Badge`, `Status`, `Person`, `MetaList`, `MetaItem`, `Facts`, `Fact`, `Metrics`, `Metric`, `Progress`, `AvatarStack`, `ItemList`, `Item`, `Steps`, `Step`, `Table`, `Chart`, `Image`, `File`, `Reference` |
| Interactive | `Button`, `Actions`, `Menu`, `MenuItem`, `MenuSeparator`, `ChoiceGroup`, `Form`, `Toggle`, `Select`, `TextInput`, `DateTimePicker`, `Tabs`, `Tab` |

`Code` is a code block. Inline code is `InlineCode`. Links are the only underlined text.

## What you describe

Props describe what something is: its structure, its numbers, its states and whether an action is
destructive. There are no `className`, `style`, colour, pixel, size, gap or emphasis props. These
values are shared across the catalog:

| Vocabulary | Values | Used by |
| - | - | - |
| Tone | `neutral`, `info`, `success`, `warning`, `danger` | `Badge`, `Callout`, `Icon`, badge cells in `Table` |
| Number format | `number`, `percent`, `currency`, `duration`, `bytes` | `Metric`, `Chart`, number columns in `Table` |
| Status state | `neutral`, `queued`, `running`, `success`, `warning`, `failure`, `done`, `cancelled`, `skipped`, `blocked` | `Status`, `Step`, status cells in `Table` |
| Intent | `destructive` | Buttons and menu items bound to a `destructive` action. The SDK sets it for you. |

Percentages are fractions: `0.08` is 8%. That applies to every `format: "percent"` value and to a
metric delta with `percent: true`.

`Text` takes `muted` and nothing else for colour. The only colour you can set is the `swatch` dot on
a `Badge` (a `#rrggbb` string), for labels that have a colour in your own product, such as an issue
label. Your app's icon is the only brand mark a block shows.

## What Reintersect decides

Reintersect decides how every block looks, the same way for every app, and no prop overrides it.

### Anatomy

Every block has the same shape: a `Header`, then the body, then one `Actions` row, then a `Footer`.
Each part is optional, but the order is fixed. The root `Actions` must be the last thing in the body.
Forms end with their own submit row. There are no other places for an `Actions` row.

### Spacing

Spacing comes from the relationship between siblings:

* Closely related pairs, such as a `Text` followed by its `MetaList`, or two `Progress` bars one
  after the other, sit 8px apart.
* Ordinary siblings sit 12px apart.
* Groups (`Section`, `Columns`, `Tabs`, `Form`, `Stack` and `Callout`) get 24px around them, twice
  the ordinary gap.

A `Divider` at the start or end of a container, or next to another divider, isn't drawn.

### The primary button

The first button in the block's root `Actions` that isn't destructive is the primary button, drawn
with a solid fill. Every other button is secondary. A destructive button is never primary: it's
outlined in the danger colour and always asks for confirmation. When a block has no root `Actions`
and exactly one `Form`, that form's submit button is primary instead. Buttons in a `Row` are small
accessory buttons and never primary.

Primary is worked out per viewer, from the buttons that viewer can see. See
[audience per button](#audience).

### Tones

Five tones carry meaning, and each one pairs a colour with a glyph and a spoken word, so the
meaning never rests on colour alone:

| Tone | Glyph | Screen readers hear |
| - | - | - |
| `neutral` | none | the label alone |
| `info` | `info` | "Note" |
| `success` | `circle-check` | "Success" |
| `warning` | `triangle-alert` | "Warning" |
| `danger` | `octagon-alert` | "Important" |

Every tone's text colour is at least 4.5:1 against the surfaces blocks sit on, in light and dark
mode. A toned badge or callout always shows its tone's glyph, so only neutral ones take an `icon`.

### Wrapping and long text

Nothing scrolls sideways, and truncated text always has a way back to the full value:

* Titles and labels wrap to two lines, then clamp.
* Short labels (badges, statuses, people, buttons, tabs, menu items, options and column headers)
  show the full value in a tooltip on hover, focus and long-press.
* Long text gets an inline **Show more**: descriptions and steps after three lines, table text cells
  after three, `Quote` after six, `Prose` after twelve, and `Text` after its `maxLines`.
* Metric values never clamp. They shrink a step, then wrap.

### Numbers

You pass numbers, and Reintersect formats them in the viewer's locale with tabular figures. Values
of a million or more are compacted, such as `1.2M`, and the exact value stays in the tooltip and the
accessible text. Deltas get their sign, arrow and colour from the number and `goodWhen`. Progress
text comes from `value`, `max` and `unit`.

### Narrow layouts

Blocks adapt to the width they're given, from a phone to a wide thread:

* A `Table` narrower than 400px becomes a list of cards. The first column is each card's title, the
  other columns become label and value pairs, and the row menu sits top right. Sortable tables get a
  **Sort** menu.
* `Columns` go side by side only when every column gets at least 200px, measured on the columns
  themselves. Otherwise they stack into one column; they never wrap as two plus one. Two columns sit
  side by side in a conversation thread, and three stack there.
* `Metrics` pick their columns from how many there are, in balanced rows: four go two by two, five go
  three and two.
* Lists below 320px move each item's trailing content under its title, and fact labels above their
  values.
* Tabs that don't fit move into a trailing **More** menu. The selected tab stays visible.
* A `ChoiceGroup` asks for an appearance. Segmented controls are used for 2 to 4 short options and
  chips for up to 8; anything else becomes a list.

### Headings and time

Heading levels are relative to where the block sits. The header is one level, sections the next,
and headings inside `Prose` fall below those, so a block never outranks the page around it.
Relative times count calendar days in the viewer's time zone, so 14 days ago reads "2 weeks ago" and
a `time` from another day shows its date too.

## Icons

Components with an `icon` prop accept a name from a fixed set of 153 Lucide icons, plus `"app"` for
your app's own icon. The type is a closed union (`IconName`), so editors complete the names and a
typo is a type error. `reintersect check` also flags icon names the host no longer knows.

Buttons, menus and menu items take an `ActionIconName`: every icon except `loader`, `chevron-down`,
`chevron-up`, `chevron-left`, `chevron-right` and `x`, which Reintersect keeps for its own controls.
`ellipsis` is allowed, since it's the natural icon for an overflow menu.

<Accordion title="Every icon name">
  `app`, `activity`, `alarm-clock`, `archive`, `arrow-down`, `arrow-left`, `arrow-right`, `arrow-up`,
  `at-sign`, `award`, `ban`, `bell`, `bell-off`, `bold`, `book`, `bookmark`, `bot`, `box`,
  `briefcase`, `bug`, `building`, `calendar`, `calendar-check`, `calendar-clock`, `camera`,
  `chart-bar`, `chart-line`, `chart-pie`, `check`, `check-check`, `chevron-down`, `chevron-left`,
  `chevron-right`, `chevron-up`, `circle`, `circle-alert`, `circle-check`, `circle-dot`,
  `circle-help`, `circle-x`, `clipboard`, `clock`, `cloud`, `code`, `cog`, `command`, `copy`, `cpu`,
  `credit-card`, `database`, `dollar-sign`, `download`, `ellipsis`, `external-link`, `eye`,
  `eye-off`, `file`, `file-text`, `filter`, `flag`, `flame`, `folder`, `gauge`, `gavel`, `gift`,
  `git-branch`, `git-commit-horizontal`, `git-fork`, `git-merge`, `git-pull-request`,
  `git-pull-request-closed`, `git-pull-request-draft`, `globe`, `hammer`, `hash`, `heart`,
  `history`, `house`, `image`, `inbox`, `info`, `key`, `laptop`, `layers`, `layout-grid`,
  `life-buoy`, `lightbulb`, `link`, `list`, `list-checks`, `list-todo`, `loader`, `lock`,
  `lock-open`, `log-in`, `log-out`, `mail`, `map-pin`, `megaphone`, `message-circle`,
  `message-square`, `mic`, `milestone`, `minus`, `monitor`, `moon`, `package`, `paperclip`,
  `pause`, `pencil`, `phone`, `pin`, `play`, `plus`, `power`, `refresh-cw`, `rocket`, `rotate-ccw`,
  `save`, `search`, `send`, `server`, `settings`, `share`, `shield`, `shield-check`, `sparkles`,
  `square`, `star`, `sun`, `tag`, `target`, `terminal`, `thumbs-down`, `thumbs-up`, `ticket`,
  `timer`, `trash`, `trending-down`, `trending-up`, `triangle-alert`, `trophy`, `undo`, `upload`,
  `user`, `user-plus`, `users`, `video`, `wand`, `webhook`, `wifi`, `wrench`, `x`, `zap`
</Accordion>

## Audience

Most container and data components accept an `audience` prop that limits who sees them:

| Value | Who sees it |
| - | - |
| `"creator"` | The member who inserted the block. Blocks your app inserts through the API have no creator, so this falls back to `"admins"`. |
| `"admins"` | Owners and admins of the block's circle, plus workspace owners and admins. |
| `{ members: ["mem_…"] }` | The listed members, at most 50. |

Inside the root `Actions`, each `Button` and `Menu` takes its own `audience`, so everyone can see
**Open** while only admins see **Merge**. Viewers see only the buttons their audience allows, the
primary button comes from those, and an `Actions` row whose buttons are all hidden from a viewer
isn't drawn for them. `<Actions audience>` hides the whole row instead.

Reintersect enforces audience on the server, so hidden parts never reach a viewer's browser. Audiences don't nest, and nothing
inside a `Form` may carry one. See [Audience](/blocks/audience-and-lifecycle#where-audience-can-go).

## Nesting rules

The types enforce some nesting rules. JSX erases every element to the same type, so the types can't
express the rules below. The server enforces them, and `reintersect check` and the testing kit run the
same validator, so a broken tree fails before you deploy:

* `Block` is the root of every block view, and appears once. Its children go `Header`, body,
  `Actions`, `Footer`, in that order.
* The root `Actions` is the last part of the body. A `Form` ends with its own submit row. `Actions`
  can't go anywhere else: not in a `Section`, `Tab`, `Column`, `Callout`, `Row` or `Stack`.
* `Actions` holds one to five `Button`s, then at most one `Menu` (or just a `Menu`). Labels are
  unique across the row. `Menu` holds only `MenuItem` and `MenuSeparator`, at most 12 items with
  unique labels.
* Sections sit at the block, tab or form level, one deep: a `Section` can't hold another `Section`.
* `Columns` holds two or three `Column`s, at the block, section, tab or form level. A `Column` can't
  hold a `Table`, `Chart`, `Prose`, `Heading` or `Code`, because those need the full width.
* `Tabs` holds two to six `Tab`s with unique labels, at the block or section level. Tabs don't nest.
* A `Form` can't hold another `Form`, and a `Stack` can't hold another `Stack`.
* `Callout` holds only text: `Text`, `Prose` and `MetaList`. Put a callout's buttons in the root
  `Actions`.
* `Row` holds one or two `Text` or `AvatarStack` elements, then up to three `Button` or `Menu`
  accessories.
* `Footer` holds one `Text` or one `MetaList`.
* `MetaList` (up to 6 items), `Facts`, `Metrics` (up to 6), `ItemList` and `Steps` hold only their
  own item component. Fact and metric labels are unique within their list.
* `Toggle`, `TextInput`, `DateTimePicker` and `Select` take a `field` from a `Form` render prop, so
  they only appear inside a `Form`.

The full list of size limits and the messages the validator reports are on [Limits](/blocks/limits).

## Not in the catalog

The catalog leaves these out on purpose, so that every block stays readable and accessible and
blocks look consistent with each other:

* Custom colours, fonts, sizes, spacing, SVG and CSS.
* Free-form grids, spacers and absolute positioning.
* Disabled controls. Hide what doesn't apply; Reintersect dims controls only when a member can't act,
  and always says why.
* Blocks nested inside blocks, and tabs inside tabs.
* Animation control.
* Raw HTML and iframes. The only embeds are the providers Reintersect already supports, such as
  YouTube, which you place with a [`Reference`](/components/data#reference) to the URL.
* Dialogs or pages opened by your app. Use a [section with a form](/blocks/sections-and-forms)
  instead.

## How each component reads as text

Reintersect projects every stored tree to plain text for agents, notifications and search. Each
component page says what that component adds to the text. These rules apply across the catalog:

* Containers join their children's text. `Section`, `Callout`, `Tabs` and `ChoiceGroup` put their
  title or label on the first line.
* Buttons and menu items read as `[Label]`; link buttons read as `[Label](https://…)`.
* `Fact` reads as `Label: value`, `Item` as a `- ` list line, and `MetaList` joins items with `·`.
* Numbers read in a stable `en-US` format, such as `Error rate: 0.4%`.
* Anything with an `audience` is left out of the shared text. Members who pass the audience get it
  merged into their own projection.
* Decorative images are left out; other images read as `[Image: alt]`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.