@reintersect/sdk/components:
"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
Frame
Block, Header, Section, Footer, DividerLayout
Stack, Row, Columns, Column, CalloutText
Text, Heading, Prose, Code, Quote, Time, Duration, Icon and rich textData
Badge, Status, Person, MetaList, Facts, Metrics, Progress, AvatarStack,
ItemList, Steps, Table, Chart, Image, File, ReferenceInteractive
Button, Actions, Menu, ChoiceGroup, Form, Toggle, Select, TextInput,
DateTimePicker, TabsRecipes
Ready-made blocks built from the catalog: approvals, polls, deployments, incidents and more.
Every export
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 noclassName, style, colour, pixel, size, gap or emphasis props. These
values are shared across the catalog:
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: aHeader, 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
Textfollowed by itsMetaList, or twoProgressbars one after the other, sit 8px apart. - Ordinary siblings sit 12px apart.
- Groups (
Section,Columns,Tabs,Form,StackandCallout) get 24px around them, twice the ordinary gap.
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 rootActions 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.
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:
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,
Quoteafter six,Proseafter twelve, andTextafter itsmaxLines. - 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 as1.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
Tablenarrower 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. Columnsgo 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.Metricspick 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
ChoiceGroupasks 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 insideProse 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 anicon 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.
Every icon name
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, zapAudience
Most container and data components accept anaudience prop that limits who sees them:
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.
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, andreintersect check and the testing kit run the
same validator, so a broken tree fails before you deploy:
Blockis the root of every block view, and appears once. Its children goHeader, body,Actions,Footer, in that order.- The root
Actionsis the last part of the body. AFormends with its own submit row.Actionscan’t go anywhere else: not in aSection,Tab,Column,Callout,RoworStack. Actionsholds one to fiveButtons, then at most oneMenu(or just aMenu). Labels are unique across the row.Menuholds onlyMenuItemandMenuSeparator, at most 12 items with unique labels.- Sections sit at the block, tab or form level, one deep: a
Sectioncan’t hold anotherSection. Columnsholds two or threeColumns, at the block, section, tab or form level. AColumncan’t hold aTable,Chart,Prose,HeadingorCode, because those need the full width.Tabsholds two to sixTabs with unique labels, at the block or section level. Tabs don’t nest.- A
Formcan’t hold anotherForm, and aStackcan’t hold anotherStack. Calloutholds only text:Text,ProseandMetaList. Put a callout’s buttons in the rootActions.Rowholds one or twoTextorAvatarStackelements, then up to threeButtonorMenuaccessories.Footerholds oneTextor oneMetaList.MetaList(up to 6 items),Facts,Metrics(up to 6),ItemListandStepshold only their own item component. Fact and metric labels are unique within their list.Toggle,TextInput,DateTimePickerandSelecttake afieldfrom aFormrender prop, so they only appear inside aForm.
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
Referenceto the URL. - Dialogs or pages opened by your app. Use a section with a form 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,TabsandChoiceGroupput their title or label on the first line. - Buttons and menu items read as
[Label]; link buttons read as[Label](https://…). Factreads asLabel: value,Itemas a-list line, andMetaListjoins items with·.- Numbers read in a stable
en-USformat, such asError rate: 0.4%. - Anything with an
audienceis 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].