Poll components
Poll renders the poll of a message. It provides PollContext and renders the poll's content: the question, the options and the buttons. MessageContent renders it for every message with a poll_id, with the poll from client.polls.fromState(message.poll_id). CreatePoll is the form that creates a poll from the composer. Polls explains how polls are created, voted on and kept current.
Best practices
- Read live poll data from
poll.state, withusePollState()oruseStateStore(poll.state, selector).message.pollis only the copy that came with the message. - Replace parts through the override keys below, and keep
Poll, which provides the context. - Render poll parts inside a message, in a
Channelor aThread. The vote button reads the user's capabilities from the channel, and the buttons read the poll and the message fromPollContext. - To show the poll's screens in your navigation instead of in modals, pass
onPressto the buttons, as Change the buttons shows. Render the screen's component, such asPollResults, with themessageandpollit receives. - Keep option texts short, so the message stays readable.
Basic usage
Poll renders without your help in every message that carries a poll. To show one elsewhere, render it with the message and the poll from the client:
import type { LocalMessage } from "stream-chat";
import { Poll, useChatContext } from "stream-chat-react-native";
export const PinnedPoll = ({ message }: { message: LocalMessage }) => {
const { client } = useChatContext();
const poll = message.poll_id
? client.polls.fromState(message.poll_id)
: undefined;
if (!poll) return null;
return <Poll message={message} poll={poll} />;
};Render it inside the Channel or Thread of the message.
Poll UI customization
Poll is built from these parts. The ones with an override key are replaced through WithComponents.
| Part | Override key | Rendered by | Shows |
|---|---|---|---|
PollContent |
PollContent |
Poll |
The whole poll: PollHeader, the first five options, ShowAllOptionsButton and PollButtons. The key has no default: without it, Poll renders the exported PollContent. |
PollHeader |
PollHeader |
PollContent |
The question, and "Select one", "Select up to 3", "Select one or more" or "Poll has ended" |
PollOption |
none | PollContent |
One option: VoteButton, the text, the avatars of the latest voters, the vote count and a bar |
VoteButton |
none | PollOption |
A checkbox, or a radio button when only one vote is allowed, while the user can vote |
ShowAllOptionsButton |
none | PollContent |
"+3 More Options", when the poll has more than five options. Opens PollAllOptions in a PollModal |
PollButtons |
PollButtons |
PollContent |
ViewResultsButton, EndVoteButton, SuggestOptionButton, AddCommentButton and ShowAllCommentsButton |
PollAllOptionsContent |
PollAllOptionsContent |
PollAllOptions |
The question and every option, with their vote buttons |
PollResultsContent |
PollResultsContent |
PollResults |
The question and the options sorted by votes, each with its five latest votes |
PollOptionFullResultsContent |
PollOptionFullResultsContent |
PollOptionFullResults |
Every vote for one option, loaded a page at a time |
PollAnswersListContent |
PollAnswersListContent |
PollAnswersList |
The comments, loaded a page at a time, with a button under the user's own comment to update it |
CreatePollContent |
CreatePollContent |
CreatePoll |
The poll creation form. The key has no default: without it, CreatePoll renders the exported CreatePollContent |
The buttons of PollButtons, and when each shows:
| Button | Shows when | Opens |
|---|---|---|
ViewResultsButton |
always | PollResults in a PollModal |
EndVoteButton |
the poll is open and the user created it | nothing: it closes the poll |
SuggestOptionButton |
the poll is open and allows suggestions | a PollInputDialog for the new option |
AddCommentButton |
the poll is open and allows comments | a PollInputDialog with the user's comment |
ShowAllCommentsButton |
the poll has comments | PollAnswersList in a PollModal |
In PollResultsContent, an option with more than five votes has ShowAllVotesButton, "Show All", when the user has the query-poll-votes capability. It opens PollOptionFullResults. VoteButton shows while the user has cast-poll-vote and the poll is open; pressing it casts the vote, or removes it when the user already voted for the option.
Replace a part
This PollContent shows three options, and keeps the SDK's header and buttons:
import { StyleSheet, View } from "react-native";
import {
PollButtons,
PollHeader,
PollOption,
usePollState,
} from "stream-chat-react-native";
import type { ComponentOverrides } from "stream-chat-react-native";
const ThreeOptionPollContent = () => {
const { options } = usePollState();
return (
<View style={styles.container}>
<PollHeader />
{options.slice(0, 3).map((option) => (
<PollOption key={option.id} option={option} />
))}
<PollButtons />
</View>
);
};
// Pass to `WithComponents`, declared once at module scope.
export const pollOverrides: ComponentOverrides = {
PollContent: ThreeOptionPollContent,
};
const styles = StyleSheet.create({
container: { gap: 12, padding: 12, width: 256 },
});The header and the buttons here are the exported defaults, so the PollHeader and PollButtons keys don't apply to this poll. Render the keys' components from useComponentsContext() to keep them. Polls replaces the header.
A part of your own that shows who voted handles anonymous polls itself, as usePollState describes.
Props
Poll
| Prop | Type | Default | Description |
|---|---|---|---|
poll |
Poll |
required | The poll, a Poll from stream-chat, from client.polls.fromState(pollId). |
message |
LocalMessage |
required | The message that carries the poll. Votes and comments are sent for it. |
PollContent, PollHeader, PollButtons, EndVoteButton and CreatePollContent take no props; they read the poll from PollContext or the form from CreatePollContentContext. PollContentProps is exported and has no members.
PollOption
| Prop | Type | Default | Description |
|---|---|---|---|
option |
PollOptionResponseData |
required | The option. |
showProgressBar |
boolean |
true |
Shows the bar under the option, its share of all votes. |
forceIncoming |
boolean |
none | Uses the colors of an incoming message, whoever created the poll. PollAllOptionsContent sets it. |
VoteButton
| Prop | Type | Default | Description |
|---|---|---|---|
option |
PollOptionResponseData |
required | The option the button votes for. |
onPress |
({ message, poll }: { message: LocalMessage; poll: Poll }) => void |
none | Called on press, in place of casting or removing the vote. |
forceIncoming |
boolean |
none | Uses the colors of an incoming message. |
style |
StyleProp<ViewStyle> |
none | Not applied. |
PollVoteButtonProps is the type of these props.
Buttons
ViewResultsButton, ShowAllOptionsButton, SuggestOptionButton, AddCommentButton, ShowAllCommentsButton and AnswerListAddCommentButton take PollButtonProps:
| Prop | Type | Default | Description |
|---|---|---|---|
onPress |
({ message, poll }: { message: LocalMessage; poll: Poll }) => void |
none | Called on press with the message and the poll, in place of opening the button's modal or dialog. |
ShowAllVotesButton takes ShowAllVotesButtonProps:
| Prop | Type | Default | Description |
|---|---|---|---|
option |
PollOptionResponseData |
required | The option whose votes it opens. |
onPress |
({ message, option, poll, }: { message: LocalMessage; option: PollOptionResponseData; poll: Poll; }) => void |
none | Called on press, in place of opening PollOptionFullResults. |
GenericPollButton is the button they render, for a button of your own. It takes GenericPollButtonProps, every prop of the SDK's Button made optional, with variant "secondary", type "ghost" and size "sm" by default. Its main props are label, onPress, LeadingIcon, TrailingIcon, iconOnly, selected, variant ("primary", "secondary" or "destructive"), type ("solid", "outline" or "ghost"), size ("sm", "md" or "lg"), accessibilityLabelKey and accessibilityLabelParams; see Buttons and inputs.
Poll screens
Each screen takes the message and the poll, provides PollContext with them, and renders its content override. A screen of your own renders them with what a button's onPress received.
| Component | Props | Renders |
|---|---|---|
PollResults |
message: LocalMessage, poll: Poll, additionalScrollViewProps?: Partial<ScrollViewProps> |
PollResultsContent |
PollAllOptions |
message: LocalMessage, poll: Poll, additionalScrollViewProps?: Partial<ScrollViewProps> |
PollAllOptionsContent |
PollAnswersList |
message: LocalMessage, poll: Poll, additionalFlatListProps?: Partial<FlatListProps<PollVoteResponseData>> |
PollAnswersListContent |
PollOptionFullResults |
message: LocalMessage, poll: Poll, option: PollOptionResponseData, additionalFlatListProps?: Partial<FlatListProps<PollVoteClass>> |
PollOptionFullResultsContent |
The content overrides get the same props without message and poll: additionalScrollViewProps, additionalFlatListProps and, for PollOptionFullResultsContent, option. The additional props are spread onto the ScrollView or FlatList after the SDK's own, so they replace them. PollResultsProps, PollAllOptionsContentProps, PollAnswersListProps and PollOptionFullResultsProps are the screens' prop types. PollVoteClass is PollVoteResponseData from stream-chat.
PollResultsItem renders one option in the results, with option: PollOptionResponseData and its index: number in the sorted list. PollAnswerListItem renders one comment, with answer: PollVoteResponseData; it hides the author of another user's comment in an anonymous poll, and renders AnswerListAddCommentButton under the user's own.
PollModal
PollModal is the React Native Modal the buttons open their screens in. It presents as a page sheet on iOS and draws under the system bars on Android.
| Prop | Type | Default | Description |
|---|---|---|---|
visible |
boolean |
none | Whether the modal is open. |
onRequestClose |
() => void |
none | Called when the user dismisses it, such as with the Android back button. |
animationType |
ModalProps['animationType'] |
"slide" |
How it opens. |
children |
ReactNode |
none | The screen. |
PollModalHeader is the header of the screens:
| Prop | Type | Default | Description |
|---|---|---|---|
title |
string |
required | The title. |
onPress |
() => void |
required | Called by the close button. |
PollInputDialog is the dialog of SuggestOptionButton and AddCommentButton:
| Prop | Type | Default | Description |
|---|---|---|---|
visible |
boolean |
required | Whether the dialog is open. |
title |
string |
required | The title. |
placeholder |
string |
required | The input's placeholder. |
onSubmit |
(text: string) => void |
required | Called with the text when the user submits. |
closeDialog |
() => void |
required | Closes the dialog. |
initialValue |
string |
"" |
The text the input starts with. |
CreatePoll
CreatePoll provides CreatePollContentContext and renders the CreatePollContent override, or the default form. MessageComposer renders it in a PollModal while the poll creation dialog is open. When it unmounts, it resets the composer's pollComposer.
| Prop | Type | Default | Description |
|---|---|---|---|
sendMessage |
() => Promise<void> |
required | Sends the composer's message after the poll is created. MessageComposer passes sendMessage from MessageInputContext. |
closePollCreationDialog |
() => void |
none | Called to close the form, after a send or by the back button of its header. |
createPollOptionGap |
number |
8 |
The gap between the options of the form, in points. |
The default form has a header with a back button and a send button, the question, the options, which the user can drag to reorder, and switches for multiple votes with a maximum, anonymous voting, suggested options and comments. Each field writes into messageComposer.pollComposer. The SDK exports CreatePollOptions, the list of options, and MultipleVotesSettings, the multiple-votes switch and its maximum, for a form of your own built from them; the question field and the header aren't exported.
PollContext
Poll and the poll screens provide PollContext. usePollContext() reads it, and throws outside one.
| Value | Type | Description |
|---|---|---|
poll |
Poll |
The Poll instance from client.polls. |
message |
LocalMessage |
The message that carries the poll. |
PollContext and PollContextProvider, which takes a value of this type, are exported too. The poll's state is in poll.state; Poll hooks lists its fields and what usePollState() returns.
CreatePollContentContext
CreatePoll provides CreatePollContentContext. useCreatePollContentContext() reads it, and throws outside CreatePoll.
| Value | Type | Description |
|---|---|---|
createAndSendPoll |
() => Promise<void> |
Creates the poll with MessageComposer.createPoll(), sends the message with sendMessage(), and closes the form. When either step throws, it logs the error and leaves the form open. |
sendMessage |
() => Promise<void> |
The CreatePoll prop. |
closePollCreationDialog |
() => void |
Closes the form. It marks the form as closing for one frame, so the fields leave without their exit animations, then calls the CreatePoll prop. |
createPollOptionGap |
number |
The CreatePoll prop, 8 by default. |
modalStateStore |
StateStore<CreatePollModalState> |
A store with isClosing, true while the form closes. MultipleVotesSettings reads it to skip its exit animation. |
A CreatePollContent of your own reads the form's data from useMessageComposer().pollComposer and calls createAndSendPoll() and closePollCreationDialog() from here. Create polls from your own UI replaces the whole sheet instead.
Examples
Show the user's votes
import { Text } from "react-native";
import { usePollState } from "stream-chat-react-native";
export const MyVotes = () => {
const { options, ownVotesByOptionId } = usePollState();
const chosen = options.filter((option) => ownVotesByOptionId[option.id]);
if (!chosen.length) return <Text>You haven't voted yet.</Text>;
return (
<Text>You voted for {chosen.map(({ text }) => text).join(", ")}.</Text>
);
};Render it inside a poll part, for example in your own PollContent.
Related hooks
| Hook | Returns |
|---|---|
usePollContext() |
{ poll, message }; throws outside a Poll |
usePollState() |
the poll's state, and addOption, addComment and endVote |
usePollStateStore(selector) |
a selection of poll.state |
usePollAnswersPagination() |
the poll's comments, a page at a time |
usePollOptionVotesPagination({ option }) |
the votes for one option, a page at a time |
useCreatePollContentContext() |
the values above; throws outside CreatePoll |
See Poll hooks.