Poll widgetPro
A poll that lives in the thread, with results that grow from each row as votes arrive and an owner close that names the winner.
On this page
Installation
Usage
import { PollWidget } from "@/components/ui/chatcn/pro/poll-widget"
<PollWidget
question="Where should the winter offsite be?"
options={options}
closesIn="Fri 18:00"
onVote={(ids) => castVote(ids)}
onClose={closePoll}
/>Each option carries the votes from everyone else, and the viewer's own vote is added from vote, so an optimistic vote never double counts. Once someone has voted, or peeks with See results, the rows turn into their own results: a soft fill and a hairline grow from the start edge to each option's share, and they keep moving as new counts arrive. Percentages are whole numbers that always add up to 100.
With maxChoices above one the options become checkboxes and the rest disable at the cap. A vote whose promise rejects is taken back and the reason is shown under the footer. onClose adds Close poll for the owner; status="closed" locks the poll and names the winner, or the tie.
Render it inside the card your host draws for a widget answer. It fills the width it is given, so a comfortable max width (around 28 rem) comes from the card, and it follows the host theme through the kit tokens. Pass onExpand where the host can go full screen.
Examples
States
Props
| Prop | Type | Notes |
|---|---|---|
question | string | Wraps to two lines |
options | { id, label, votes, detail? }[] | Votes from everyone else |
author, closesIn, anonymous | The meta line | |
maxChoices | number | Default 1 |
vote, defaultVote | string[] | null | The viewer's vote |
onVote | (ids) => unknown | Promise | A rejection rolls the vote back |
onClose | () => unknown | Promise | Owner action |
peek | boolean | See results before voting. Default true |
status | "open" | "closed" | "loading" | "error" | Default open |
voteError | ReactNode | A failure reported outside the promise |
locale, onRetry, disabled | ||
labels | Partial<…Labels> | Every string the widget writes, for translation |
Labels
labels covers the prompt, every button, the vote count (votes(n, count), where count is already formatted), the voted, won and tie lines (join builds the list of names), the closing time prefix and every error.
Keyboard
| Key | Action |
|---|---|
| Tab | Into the options, then the footer buttons |
| Arrow keys | Move between options in a single choice poll |
| Space | Pick or drop an option |
Accessibility
- Options are native radios or checkboxes in a fieldset whose legend says how many to pick.
- Results are an ordered list in a polite live region. Each row gives the percentage and the count as text; your own vote carries a named check, and the leader is marked by weight as well as the accent hairline.
- The winner line uses an icon and words, never color alone.
Motion
Result fills scale from the start edge in 280 ms with the kit's ease out and follow new votes without restarting. Reduced motion jumps to the new share.