- API AccessPublic API for third-party integrations
- Mobile AppNative iOS and Android applications
- Dark ModeAdd system-wide dark mode support with automatic detection
- Keyboard ShortcutsCustomizable keyboard shortcuts for power users
- Export to PDFExport documents and reports as PDF files
- Inline editing
- Batch operations
- Auto-save drafts
Installation
pnpm dlx shadcn@latest add https://cult-ui.com/r/vote-tally.json
Usage
Use VoteTally.Root with VoteTally.Item for each item; each item can include Trigger, Title, Description, and Count. Supports controlled or uncontrolled vote counts and voted-items state, and optional sorting via VoteTally.Group.
Basic list
import { VoteTally } from "@/registry/default/ui/vote-tally"
export default function Example() {
return (
<VoteTally.Root>
<VoteTally.Item value="dark-mode">
<VoteTally.Title>Dark mode</VoteTally.Title>
<VoteTally.Description>System-aware dark theme</VoteTally.Description>
<VoteTally.Count />
<VoteTally.Trigger>Vote</VoteTally.Trigger>
</VoteTally.Item>
<VoteTally.Item value="keyboard-shortcuts">
<VoteTally.Title>Keyboard shortcuts</VoteTally.Title>
<VoteTally.Description>Customizable hotkeys</VoteTally.Description>
<VoteTally.Count />
<VoteTally.Trigger>Vote</VoteTally.Trigger>
</VoteTally.Item>
</VoteTally.Root>
)
}Controlled votes and voted items
Wire value / onValueChange and votedItems / onVotedItemsChange to sync with your backend or state.
import { useState } from "react"
import { VoteTally } from "@/registry/default/ui/vote-tally"
export default function Example() {
const [votes, setVotes] = useState({ "dark-mode": 10, "keyboard-shortcuts": 5 })
const [voted, setVoted] = useState(new Set<string>())
return (
<VoteTally.Root
value={votes}
onValueChange={setVotes}
votedItems={voted}
onVotedItemsChange={setVoted}
>
<VoteTally.Item value="dark-mode">
<VoteTally.Title>Dark mode</VoteTally.Title>
<VoteTally.Count />
<VoteTally.Trigger>Vote</VoteTally.Trigger>
</VoteTally.Item>
<VoteTally.Item value="keyboard-shortcuts">
<VoteTally.Title>Keyboard shortcuts</VoteTally.Title>
<VoteTally.Count />
<VoteTally.Trigger>Vote</VoteTally.Trigger>
</VoteTally.Item>
</VoteTally.Root>
)
}With sorting by votes
Wrap items in VoteTally.Group with sortBy="votes-desc" or sortBy="votes-asc" to reorder by vote count.
import { VoteTally } from "@/registry/default/ui/vote-tally"
export default function Example() {
return (
<VoteTally.Root defaultValue={{ a: 2, b: 5, c: 1 }}>
<VoteTally.Group sortBy="votes-desc">
<VoteTally.Item value="a">
<VoteTally.Title>Option A</VoteTally.Title>
<VoteTally.Count />
<VoteTally.Trigger>Vote</VoteTally.Trigger>
</VoteTally.Item>
<VoteTally.Item value="b">
<VoteTally.Title>Option B</VoteTally.Title>
<VoteTally.Count />
<VoteTally.Trigger>Vote</VoteTally.Trigger>
</VoteTally.Item>
<VoteTally.Item value="c">
<VoteTally.Title>Option C</VoteTally.Title>
<VoteTally.Count />
<VoteTally.Trigger>Vote</VoteTally.Trigger>
</VoteTally.Item>
</VoteTally.Group>
</VoteTally.Root>
)
}Features
- Vote and unvote per item via Trigger; one vote per user per item (tracked by
votedItems) - Controlled or uncontrolled:
value/defaultValueandonValueChangefor vote counts;votedItems/defaultVotedItemsandonVotedItemsChangefor which items the user voted for - Optional sorting:
VoteTally.GroupwithsortBy="votes-asc"orsortBy="votes-desc" - Compound API: Root, Group, Item, Trigger, Count, Title, Description
useVoteTally()hook for external access to vote state and actions