# Poll components

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

`Poll` renders the poll of a message. It provides `PollContext` and renders the `PollContent` override: the question, the options and the actions. The default `MessageUI` renders it for every message with a `poll_id`, with the poll from `client.polls.fromState(message.poll_id)`. [Polls](https://getstream.io/chat/docs/sdk/react/v15/features/rich-content/polls/) explains how polls are created, voted on and kept current.

## Best practices

- Read live poll data from `poll.state`. `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`. `PollActions` and `PollOptionSelector` read the message from `useMessageContext()` and the user's capabilities from the channel.
- Keep option texts short, so the message stays readable.
- A quoted poll has no poll UI. The quoted message shows a poll icon and, when it has no text, the poll's name.

## Poll UI customization

`Poll` is built from these parts. The ones with an override key are replaced through `WithComponents`; the others through the props of the part that renders them.

| Part                  | Override key         | Rendered by          | Shows                                                                                                                                       |
| --------------------- | -------------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| `PollContent`         | `PollContent`        | `Poll`               | The whole poll: `PollHeader`, `PollOptionList` and `PollActions`                                                                            |
| `PollHeader`          | `PollHeader`         | `PollContent`        | The question and how many options can be chosen, or "Vote ended"                                                                            |
| `PollOptionList`      | none                 | `PollContent`        | A `PollOptionSelector` per option, and a button for the full list                                                                           |
| `PollOptionSelector`  | `PollOptionSelector` | `PollOptionList`     | One option: a checkbox while the user can vote, the text, the votes and a bar                                                               |
| `PollOptionsFullList` | none                 | `PollOptionList`     | Every option, in a dialog                                                                                                                   |
| `PollActions`         | `PollActions`        | `PollContent`        | The buttons below the options and the dialogs they open                                                                                     |
| `PollCreationDialog`  | `PollCreationDialog` | `AttachmentSelector` | The form that creates a poll; see [Attachment Selector](https://getstream.io/chat/docs/sdk/react/v15/component-reference/message-composer/attachment-selector/) |

`PollContent` shows five options, and a button that opens the full list when there are more. Each `PollActions` button shows only when it applies:

| Button                                | Shows when                                                                                                        | Opens                   |
| ------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | ----------------------- |
| End Poll                              | The poll is open and the user created it                                                                          | `EndPollAlert`          |
| View Results                          | The poll has votes                                                                                                | `PollResults`           |
| Suggest an Option                     | The user can vote (`cast-poll-vote`, poll open), suggestions are allowed, and the poll has fewer than 100 options | `SuggestPollOptionForm` |
| Add a Comment, or Update Your Comment | The poll is open and allows comments                                                                              | `AddCommentPrompt`      |
| View Comments                         | The poll has comments and the user has `query-poll-votes`                                                         | `PollAnswerList`        |

### Replace a dialog

`PollActions` takes the dialogs it opens as props. Wrap it to replace one and keep the others, and register the wrapper as the `PollActions` override. This one replaces the form that suggests an option:

```tsx
import { useState } from "react";
import type { FormEvent, PropsWithChildren } from "react";
import {
  PollActions,
  useModalContext,
  usePollContext,
  WithComponents,
} from "stream-chat-react";

const SuggestOptionForm = () => {
  const { poll } = usePollContext();
  const { close } = useModalContext();
  const [text, setText] = useState("");

  const submit = async (event: FormEvent<HTMLFormElement>) => {
    event.preventDefault();
    try {
      await poll.createOption({ text: text.trim() });
      close();
    } catch {
      // The option wasn't added. Show the error in the form here.
    }
  };

  return (
    <form className="suggest-option-form" onSubmit={submit}>
      <input
        aria-label="Option"
        onChange={(event) => setText(event.target.value)}
        value={text}
      />
      <button disabled={!text.trim()} type="submit">
        Suggest
      </button>
    </form>
  );
};

const PollActionsWithOwnSuggestion = () => (
  <PollActions SuggestPollOptionForm={SuggestOptionForm} />
);

const overrides = { PollActions: PollActionsWithOwnSuggestion };

export const WithOwnPollSuggestions = ({ children }: PropsWithChildren) => (
  <WithComponents overrides={overrides}>{children}</WithComponents>
);
```

The dialog's frame stays the SDK's, and `useModalContext()` closes it. [Polls](https://getstream.io/chat/docs/sdk/react/v15/features/rich-content/polls/#replace-the-action-dialogs) replaces `EndPollAlert` the same way.

### Change the layout

Override `PollContent` and arrange the parts. `PollOptionList` takes the full-list dialog as `PollOptionsFullList`:

```tsx
import type { PollState } from "stream-chat";
import {
  PollActions,
  PollHeader,
  PollOptionList,
  usePollContext,
  useStateStore,
} from "stream-chat-react";

const optionsSelector = ({ options }: PollState) => ({ options });

const OptionTexts = () => {
  const { poll } = usePollContext();
  const { options } = useStateStore(poll.state, optionsSelector);

  return (
    <ul>
      {options.map((option) => (
        <li key={option.id}>{option.text}</li>
      ))}
    </ul>
  );
};

// Register as the PollContent override.
export const PollContentWithThreeOptions = () => (
  <div className="str-chat__poll">
    <PollHeader />
    <PollOptionList optionsDisplayCount={3} PollOptionsFullList={OptionTexts} />
    <PollActions />
  </div>
);
```

## Props

### Poll

| Prop   | Type   | Default  | Description                                                          |
| ------ | ------ | -------- | -------------------------------------------------------------------- |
| `poll` | `Poll` | required | The poll, a `Poll` from `stream-chat`. Without one, nothing renders. |

`PollContent`, `PollHeader`, `PollOptionsFullList`, `PollResults` and `EndPollAlert` take no props; they read the poll from `PollContext`.

### PollOptionList

| Prop                  | Type                  | Default               | Description                                                                                                |
| --------------------- | --------------------- | --------------------- | ---------------------------------------------------------------------------------------------------------- |
| `optionsDisplayCount` | `number`              | every option          | How many options to show. With more options, a button opens `PollOptionsFullList`. `PollContent` passes 5. |
| `PollOptionsFullList` | `React.ComponentType` | `PollOptionsFullList` | The dialog content that lists every option.                                                                |

### PollOptionSelector

| Prop                 | Type                     | Default  | Description                                                                                                     |
| -------------------- | ------------------------ | -------- | --------------------------------------------------------------------------------------------------------------- |
| `option`             | `PollOptionResponseData` | required | The option.                                                                                                     |
| `displayAvatarCount` | `number`                 | none     | How many avatars of the latest voters to show. They show only when votes are public. `PollOptionList` passes 3. |
| `voteCountVerbose`   | `boolean`                | `false`  | Shows "2 votes" instead of "2".                                                                                 |

Clicking the option, or pressing Enter or Space on it, casts or removes the user's vote.

### PollActions

| Prop                    | Type                                              | Default                   | Description                         |
| ----------------------- | ------------------------------------------------- | ------------------------- | ----------------------------------- |
| `AddCommentPrompt`      | `React.ComponentType<AddCommentPromptProps>`      | `AddCommentPrompt`        | Adds or updates the user's comment. |
| `EndPollAlert`          | `React.ComponentType`                             | `EndPollAlert`            | Confirms ending the poll.           |
| `PollAnswerList`        | `React.ComponentType<PollAnswerListProps>`        | `PollAnswerList`          | Lists the comments.                 |
| `PollResults`           | `React.ComponentType`                             | `PollResults`             | Shows the results by option.        |
| `SuggestPollOptionForm` | `React.ComponentType<SuggestPollOptionFormProps>` | `SuggestPollOptionPrompt` | Suggests a new option.              |

The dialogs' own props:

| Component            | Props                                                                      |
| -------------------- | -------------------------------------------------------------------------- |
| `AddCommentPrompt`   | `messageId: string`, the message that carries the poll                     |
| `PollAnswerList`     | `onUpdateOwnAnswerClick: () => void`, which switches to `AddCommentPrompt` |
| `PollCreationDialog` | `close: () => void`, which closes the dialog                               |
| `PollVote`           | `vote: PollVoteResponseData`, one vote with its author and time            |
| `PollVoteListing`    | `votes: PollVoteResponseData[]`                                            |

## Poll API and state

`poll.state` is a store of `PollState`: the poll's data from the server, such as `name`, `options`, `vote_counts_by_option`, `latest_votes_by_option`, `is_closed` and `vote_count`, plus four values the client derives:

- `ownVotesByOptionId`: the user's votes, by option id;
- `ownAnswer`: the user's comment;
- `maxVotedOptionIds`: the options with the most votes;
- `lastActivityAt`: when the client last updated the poll from the server, in Unix nanoseconds.

The `Poll` instance has the methods `query`, `update`, `partialUpdate`, `close`, `delete`, `createOption`, `updateOption`, `deleteOption`, `castVote`, `removeVote`, `addAnswer`, `removeAnswer`, `queryAnswers` and `queryOptionVotes`. `castVote`, `removeVote` and `close` update `poll.state` before the server answers; see [Voting and keeping the poll current](https://getstream.io/chat/docs/sdk/react/v15/features/rich-content/polls/#voting-and-keeping-the-poll-current).

>
> **Warning:** Don't read votes from `MessageContext`'s `message.poll`. Read `poll.state`.
>

## PollContext

`Poll` provides `PollContext` to its parts. `usePollContext()` reads it, and throws outside a `Poll`.

| Value  | Type   | Description                              |
| ------ | ------ | ---------------------------------------- |
| `poll` | `Poll` | The `Poll` instance from `client.polls`. |

`PollProvider` is exported too. It takes `poll` and renders nothing without one.

## Examples

### Show the user's votes

```tsx
import type { PollState } from "stream-chat";
import { usePollContext, useStateStore } from "stream-chat-react";

const ownVotesSelector = ({ options, ownVotesByOptionId }: PollState) => ({
  options,
  ownVotesByOptionId,
});

export const MyVotes = () => {
  const { poll } = usePollContext();
  const { options, ownVotesByOptionId } = useStateStore(
    poll.state,
    ownVotesSelector,
  );
  const chosen = options.filter((option) => ownVotesByOptionId[option.id]);

  if (!chosen.length) return <span>You haven't voted yet.</span>;

  return (
    <span>You voted for {chosen.map(({ text }) => text).join(", ")}.</span>
  );
};
```

Render it inside a poll part, for example in your own `PollContent`.

## Related hooks

| Hook                                                 | Returns                                      |
| ---------------------------------------------------- | -------------------------------------------- |
| `usePollContext()`                                   | `{ poll }`; throws outside a `Poll`          |
| `usePollAnswerPagination({ paginationParams? })`     | the poll's comments, a page at a time        |
| `usePollOptionVotesPagination({ paginationParams })` | the votes for one option, a page at a time   |
| `useCanCreatePoll()`                                 | whether the composer's poll form can be sent |

See [Poll hooks](https://getstream.io/chat/docs/sdk/react/v15/reference/hooks/poll-hooks/) and [useCanCreatePoll](https://getstream.io/chat/docs/sdk/react/v15/reference/hooks/composer-hooks/#usecancreatepoll).

---

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