Skip to main content
Interactive components run your actions or collect viewer input. Read-only views, such as share pages and connected workspaces, hide actions, menus, forms and inputs, and keep link and copy buttons. Controls have no disabled prop, so hide a control that doesn’t apply. When a member can’t act on a block, for example because the circle is read-only for them or the block is final, Reintersect dims the controls and shows the reason under them.

Button

A button that runs an action, opens a link, copies text or opens a section. Pick one with type, which defaults to "action". Each type takes exactly the props it needs, and a prop for another type is a type error. Buttons go in two places: the block’s root Actions, where Reintersect decides which one is primary, and a Row, where they’re small accessory buttons. A form’s submit button comes from its submitLabel.
Props every type accepts: There’s no prop for emphasis or size. The first button in the root Actions that isn’t destructive is primary, the rest are secondary, and buttons in a Row are small accessories.

Destructive actions and confirm

When an action is defined with destructive: true, the SDK marks every button and menu item bound to it with intent: "destructive", and confirm becomes required: leaving it out is a type error and a runtime error. A destructive button is outlined in the danger colour and is never primary. confirm is { title, body? }: a title of up to 80 characters and an optional body of up to 280. The dialog’s confirm button repeats the label of the button that opened it, its Cancel button gets focus first, and it uses the danger style only for destructive actions. A non-destructive action can still ask for confirmation with confirm. Pass an action with arguments as actions.move.with({ id, status }); leaving out .with() when the action declares args is a type error. In agent text, most buttons read as [Label] and link buttons as [Label](https://…).

Actions

The block’s row of buttons. Use it for the main things a viewer can do with the block. It’s the last part of the block’s body, before the Footer, and a block has at most one. Sections, tabs, columns, callouts and stacks can’t hold an Actions row: put their buttons here, or in a Row next to the text they act on.
Each Button and Menu in the row can take its own audience. Viewers see only the buttons their audience allows, and the primary button is the first visible one that isn’t destructive. In the example, admins see Merge as the primary button, and everyone else sees Open pull request as primary. When every button in the row is hidden from a viewer, the row isn’t drawn for them. Labels are unique across the whole row, including hidden buttons and the menu’s label. When the row is narrower than 280px, the buttons stack at full width, primary first. A button that opens a list of actions, links and copy items. Use it when a block has more than a few secondary actions. A menu goes at the end of the root Actions or in a Row.
MenuSeparator takes no props. Separators at the start or end of a menu, or next to another separator, aren’t drawn. A menu with a single item is drawn as a secondary button with that item’s label. A copy item confirms inline, without a toast. In agent text, a menu reads as Label: [Item] [Item].

ChoiceGroup

A set of choices bound to an input the block declares with choice(). Use it for polls, votes and RSVPs. Each member’s pick is stored per viewer, and Reintersect keeps the counts. See Viewer inputs.
appearance is a request that Reintersect downgrades when the choices won’t fit it: "segmented" is used for 2 to 4 choices of up to 16 characters each, "chips" for up to 8 choices, and anything else shows as a list. Fill bars always come from the counts. Whether the input allows several picks and whether voters stay anonymous comes from the input’s declaration (choice(values, { multiple, anonymous })), not from the component. To stop new picks, for example when a poll closes, return final from the closing action or stop rendering the group. Agent text lists each choice with its current count.

Form

Collects input for one action. Use it when an action needs more than a click, such as a reason for a rejection. The action declares an input schema, and Form hands you one typed field per property through a render prop.
The form ends with its own row holding only the submit button, so there’s no cancel button. A form’s submit button is primary when the block has no root Actions and this is its only form; otherwise it’s secondary. A form sits at the block, section or tab level, and forms don’t nest. Field values live in the viewer’s browser until they submit. If your action returns fieldErrors, Reintersect shows each message next to its field. See Sections and forms.

TextInput

A single-line or multi-line text field inside a Form. Use it for free text, such as a title or a reason.

Toggle

An on and off switch inside a Form. Use it for a yes or no choice, such as whether to notify a channel.

DateTimePicker

A date or date and time field inside a Form. Use it to ask for a date, such as a due date.

Select

A dropdown inside a Form, with static options or options your app searches. Use it to pick one value from a list, such as a priority or a project.
A search action receives the typed text as query in its context and returns { options }, at most 50 items of { value, label, description? }. Reintersect debounces typing and starts searching at two characters. If the search fails, the menu says “Couldn’t search. Try again.” with a retry button. Mark search actions readOnly: true so agents and approvals treat them as reads:

Tabs and Tab

Groups content under tabs. Use it when a block has several views of one thing, such as a pull request’s checks and files. Switching tabs happens in the viewer’s browser. Read-only views and agent text show every tab, one after the other, under its label.
Tabs sit at the block or section level. Tabs that don’t fit the width move into a trailing More menu, and the selected tab always stays visible.