# Poll components

> **Info:** This is release candidate documentation for **Stream Chat React Native SDK v10**. For the latest stable version, see the [latest version (v9)](https://getstream.io/chat/docs/sdk/react-native/).

`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](https://getstream.io/chat/docs/sdk/react-native/v10/features/rich-content/polls/) explains how polls are created, voted on and kept current.

## Best practices

- Read live poll data from `poll.state`, with `usePollState()` or `useStateStore(poll.state, selector)`. `message.poll` is 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 `Channel` or a `Thread`. The vote button reads the user's capabilities from the channel, and the buttons read the poll and the message from `PollContext`.
- To show the poll's screens in your navigation instead of in modals, pass `onPress` to the buttons, as [Change the buttons](https://getstream.io/chat/docs/sdk/react-native/v10/features/rich-content/polls/#change-the-buttons) shows. Render the screen's component, such as `PollResults`, with the `message` and `poll` it 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:

```tsx title="src/PinnedPoll.tsx"
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:

```tsx title="src/pollOverrides.tsx"
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](https://getstream.io/chat/docs/sdk/react-native/v10/features/rich-content/polls/#replace-part-of-the-poll) replaces the header.

A part of your own that shows who voted handles anonymous polls itself, as [usePollState](https://getstream.io/chat/docs/sdk/react-native/v10/reference/hooks/poll-hooks/#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](https://getstream.io/chat/docs/sdk/react-native/v10/component-reference/base-ui/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](https://getstream.io/chat/docs/sdk/react-native/v10/reference/hooks/poll-hooks/#poll-state-fields) 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](https://getstream.io/chat/docs/sdk/react-native/v10/features/rich-content/polls/#create-polls-from-your-own-ui) replaces the whole sheet instead.

## Examples

### Show the user's votes

```tsx title="src/MyVotes.tsx"
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](https://getstream.io/chat/docs/sdk/react-native/v10/reference/hooks/poll-hooks/).

---

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/react-native/v10/component-reference/poll-components/](https://getstream.io/chat/docs/sdk/react-native/v10/component-reference/poll-components/).