Skip to main content
A viewer input is a choice each member makes for themselves: a vote, an RSVP, a go or no-go call. Reintersect stores each member’s pick and keeps the counts live for every viewer. Your render function never sees individual picks, so one shared tree serves everyone.

Declare an input

Declare inputs on the block with choice(), then render them with a ChoiceGroup:
choice(values, options) takes 1 to 20 values (each 1 to 64 characters from A-Z, a-z, 0-9, _, . and -) and these options: labels must name every declared value; a missing one is a type error. Labels are up to 60 characters and unique within the group. Each input may be rendered once: input and field names are unique across the whole block, including across two forms. appearance is a preference. Reintersect uses a segmented control for 2 to 4 short choices and chips for up to 8, and falls back to a list when the choices don’t fit.

What members see

With the default scope="viewer" and results="host":
  • A member’s pick shows immediately. Reintersect saves it in the background with no pending state.
  • Every viewer sees live counts and fill bars, and, unless the input is anonymous, the faces of the members behind each choice.
  • With clearable, a member can take back a single pick.
  • When the block becomes final, picks stop and the last counts stay. There’s no disabled prop, so closing a vote means returning final from an action, as close does below, or no longer rendering the group.
Read-only views (share pages and connected workspaces) show the counts without voters. Agent text lists each choice with its current count.

Read tallies in an action

The render function doesn’t receive tallies, because one tree serves every viewer and counts change without a re-render. Actions read them. Declare the inputs an action needs with inputs:
tallies.verdict is typed by the declared values, so tallies.verdict.maybe is a type error. An action that tallies an input its block doesn’t declare fails to attach.

Results modes

Shared choices

scope="shared" turns the group into one control for the whole block instead of one per member. The pick isn’t stored per member: it goes to the group’s onChange action as input: { [inputName]: values }, and your action decides what to store in state. A shared group outside a form must have onChange, because the action is the only place a shared value is kept; reintersect check and Reintersect reject one without it.
A ChoiceGroup inside a Form is a form field instead: its picks are submitted with the rest of the form’s input.

Audience and anonymity

Tallies follow audience. Counts for a ChoiceGroup inside an audience-limited part of a block are visible only to members who pass that audience. Anonymous inputs never record voters, so facepiles and voters stay empty.

Test it

The testing kit records votes and reads tallies the same way Reintersect does: