diff --git a/docusaurus/docs/React/assets/add-poll-comment-form.png b/docusaurus/docs/React/assets/add-poll-comment-form.png
new file mode 100644
index 000000000..bed1b19d8
Binary files /dev/null and b/docusaurus/docs/React/assets/add-poll-comment-form.png differ
diff --git a/docusaurus/docs/React/assets/dashboard-channel-type-feature-configuration-ui.png b/docusaurus/docs/React/assets/dashboard-channel-type-feature-configuration-ui.png
new file mode 100644
index 000000000..b9f32bda7
Binary files /dev/null and b/docusaurus/docs/React/assets/dashboard-channel-type-feature-configuration-ui.png differ
diff --git a/docusaurus/docs/React/assets/dashboard-roles-permissions-ui.png b/docusaurus/docs/React/assets/dashboard-roles-permissions-ui.png
new file mode 100644
index 000000000..871baba4b
Binary files /dev/null and b/docusaurus/docs/React/assets/dashboard-roles-permissions-ui.png differ
diff --git a/docusaurus/docs/React/assets/end-poll-dialog.png b/docusaurus/docs/React/assets/end-poll-dialog.png
new file mode 100644
index 000000000..bb7647821
Binary files /dev/null and b/docusaurus/docs/React/assets/end-poll-dialog.png differ
diff --git a/docusaurus/docs/React/assets/message-with-poll.png b/docusaurus/docs/React/assets/message-with-poll.png
new file mode 100644
index 000000000..54184f88c
Binary files /dev/null and b/docusaurus/docs/React/assets/message-with-poll.png differ
diff --git a/docusaurus/docs/React/assets/poll-comment-list.png b/docusaurus/docs/React/assets/poll-comment-list.png
new file mode 100644
index 000000000..415a9066f
Binary files /dev/null and b/docusaurus/docs/React/assets/poll-comment-list.png differ
diff --git a/docusaurus/docs/React/assets/poll-creation-dialog.png b/docusaurus/docs/React/assets/poll-creation-dialog.png
new file mode 100644
index 000000000..4c4abf320
Binary files /dev/null and b/docusaurus/docs/React/assets/poll-creation-dialog.png differ
diff --git a/docusaurus/docs/React/assets/poll-option-full-list.png b/docusaurus/docs/React/assets/poll-option-full-list.png
new file mode 100644
index 000000000..c20f0cf76
Binary files /dev/null and b/docusaurus/docs/React/assets/poll-option-full-list.png differ
diff --git a/docusaurus/docs/React/assets/poll-results.png b/docusaurus/docs/React/assets/poll-results.png
new file mode 100644
index 000000000..f4df6626f
Binary files /dev/null and b/docusaurus/docs/React/assets/poll-results.png differ
diff --git a/docusaurus/docs/React/assets/suggest-poll-option-form.png b/docusaurus/docs/React/assets/suggest-poll-option-form.png
new file mode 100644
index 000000000..3a333d80a
Binary files /dev/null and b/docusaurus/docs/React/assets/suggest-poll-option-form.png differ
diff --git a/docusaurus/docs/React/components/message-components/poll.mdx b/docusaurus/docs/React/components/message-components/poll.mdx
new file mode 100644
index 000000000..4a34a68dd
--- /dev/null
+++ b/docusaurus/docs/React/components/message-components/poll.mdx
@@ -0,0 +1,194 @@
+---
+id: poll
+title: Poll
+---
+
+Messages can contain polls. Polls are by default created using `PollCreationDialog` that is invoked from [`AttachmentSelector`](../../message-input-components/attachment-selector). Messages that render polls are not editable. Polls can be only closed by the poll creator. The top-level component to render the message poll data is `Poll` and it renders a header followed by option list and poll actions section.
+
+![](../../assets/message-with-poll.png)
+
+## Poll UI customization
+
+The following part of the poll UI can be customized:
+
+- `QuotedPoll` - UI rendered if the poll is rendered in a quoted message
+- `PollContent` - component that renders the whole non-quoted poll UI
+- `PollHeader` - customizes the topmost part of the poll UI
+- `PollOptionSelector` - customizes the individual clickable option selectors
+- `PollActions` - customizes the bottom part of the poll UI that consists of buttons that invoke action dialogs
+
+### Poll header customization
+
+```tsx
+import { ReactNode } from 'react';
+import { Channel } from 'stream-chat-react';
+
+const PollHeader = () =>
Custom Header
;
+
+const ChannelWrapper = ({ children }: { children: ReactNode }) => (
+ {children}
+);
+```
+
+### Poll option selector customization
+
+If we wanted to customize only the option selector we can do it with custom `PollOptionSelector` component.
+
+```tsx
+import { ReactNode } from 'react';
+import { Channel } from 'stream-chat-react';
+
+const PollOptionSelector = () =>
Custom Option Selector
;
+
+const ChannelWrapper = ({ children }: { children: ReactNode }) => (
+ {children}
+);
+```
+
+### Poll actions customization
+
+The component `PollActions` controls the display of dialogs or modals that allow user to further interact with the poll data. There are the following poll actions supported by the component that invoke corresponding dialogs resp. modals:
+
+| Action button | Visible condition | Invokes |
+| ------------------------- | ----------------------------------------------------------------------------------------- | ----------------------- |
+| See all options | option count > 10 | `PollOptionsFullList` |
+| Suggest an option | poll is not closed and `poll.allow_user_suggested_options === true` | `SuggestPollOptionForm` |
+| Add or update own comment | poll is not closed and `poll.allow_answers === true` | `AddCommentForm` |
+| View comments | `channel.own_capabilities` array contains `'query-poll-votes'` & `poll.answers_count > 0` | `PollAnswerList` |
+| View results | always visible | `PollResults` |
+| End vote | owner of the poll | `EndPollDialog` |
+
+**Default PollOptionsFullList**
+
+![](../../assets/poll-option-full-list.png)
+
+**Default SuggestPollOptionForm**
+
+![](../../assets/suggest-poll-option-form.png)
+
+**Default AddCommentForm**
+
+![](../../assets/add-poll-comment-form.png)
+
+**Default PollAnswerList**
+
+![](../../assets/poll-comment-list.png)
+
+**Default PollResults**
+
+![](../../assets/poll-results.png)
+
+**Default EndPollDialog**
+
+![](../../assets/end-poll-dialog.png)
+
+Individual dialogs and thus the whole `PollActions` component can be overridden via `PollActions` component props as follows:
+
+```tsx
+import { ReactNode } from 'react';
+import { Channel, PollActions } from 'stream-chat-react';
+import {
+ CustomAddCommentForm,
+ CustomEndPollDialog,
+ CustomPollAnswerList,
+ CustomPollOptionsFullList,
+ CustomPollResults,
+ CustomSuggestPollOptionForm,
+} from './PollActions';
+
+const CustomPollActions = () => (
+
+);
+
+const ChannelWrapper = ({ children }: { children: ReactNode }) => (
+ {children}
+);
+```
+
+### Poll contents layout customization
+
+This approach is useful when we want to change the organization of the poll UI. For the purpose we can provide custom `PollContent` component to `Channel`.
+
+```tsx
+import { ReactNode } from 'react';
+import { Channel } from 'stream-chat-react';
+import { CustomPollHeader, CustomPollOptionList } from './Poll';
+
+const PollContents = () => (
+
+
+
+
+);
+
+const ChannelWrapper = ({ children }: { children: ReactNode }) => (
+ {children}
+);
+```
+
+## Poll API and state
+
+In order to be fully capable to customize the poll UI, we need to learn how to utilize Poll API and later access the reactive poll state.
+
+First of all, the Poll API is exposed via a `Poll` instance. This instance is provided via React context to all the children of the `Poll` component that is rendered internally by `Message` component. The context can be consumed using `usePollContext` hook:
+
+```tsx
+import { usePollContext } from 'stream-chat-react';
+
+const Component = () => {
+ const { poll } = usePollContext();
+};
+```
+
+The `Poll` instance exposes the following methods:
+
+- `query` - queries the data for a given poll (permission to query polls is required)
+- `update` - overwrites the poll data
+- `partialUpdate` - overwrites only the given poll data
+- `close` - marks the poll as closed (useful for custom `EndPollDialog`)
+- `delete` - deletes the poll
+- `createOption` - creates a new option for given poll (useful for custom `SuggestPollOptionForm`)
+- `updateOption` - updates an option
+- `deleteOption` - removes the option from a poll
+- `castVote` - casts a vote to a given option (useful for custom `PollOptionSelector`)
+- `removeVote` - removes a vote from a given option (useful for custom `PollOptionSelector`)
+- `addAnswer` - adds an answer (comment)
+- `removeAnswer` - removes an answer (comment)
+- `queryAnswers` - queries and paginates answers (useful for custom `PollAnswerList`)
+- `queryOptionVotes` - queries and paginates votes for a given option (useful for option detail)
+
+The poll state can be accessed inside the custom React components using the following pattern
+
+```tsx
+import { usePollContext, useStateStore } from 'stream-chat-react';
+
+import type { PollState, PollVote } from 'stream-chat';
+import type { StreamChatGenerics } from './types';
+
+type PollStateSelectorReturnValue = {
+ latest_votes_by_option: Record[]>;
+};
+
+// 1. Define the selector function that receives the fresh value every time the observed property changes
+const pollStateSelector = (
+ nextValue: PollState,
+): PollStateSelectorReturnValue => ({ latest_votes_by_option: nextValue.latest_votes_by_option });
+
+const CustomComponent = () => {
+ // 2. Retrieve the poll instance from the context
+ const { poll } = usePollContext();
+ // 3. Use the useStateStore hook to subscribe to updates in the poll state with selector picking out only properties we are interested in
+ const { latest_votes_by_option } = useStateStore(poll.state, pollStateSelector);
+};
+```
+
+:::warning
+Do not try to access the `poll` data via `message` object available from `MessageContext`. This data is not updated and serve only as a seed, for the `poll` state.
+:::
diff --git a/docusaurus/docs/React/components/message-input-components/attachment-selector.mdx b/docusaurus/docs/React/components/message-input-components/attachment-selector.mdx
new file mode 100644
index 000000000..db0c28b46
--- /dev/null
+++ b/docusaurus/docs/React/components/message-input-components/attachment-selector.mdx
@@ -0,0 +1,120 @@
+---
+id: attachment-selector
+title: Attachment Selector
+---
+
+Messages can be enriched with attachments or polls by default. The `AttachmentSelector` component is a component that allows to select what information is to be attached to a message. The attachment objects are included in `message.attachments` property and represent various file uploads. The poll representation is available via `message.poll` property.
+
+## Enabling the default attachment selector features
+
+The configuration is possible via Stream dashboard. File uploads and poll creation can be controlled via
+
+1. role permissions
+
+![](../../assets/dashboard-roles-permissions-ui.png)
+
+2. channel type configuration
+
+![](../../assets/dashboard-channel-type-feature-configuration-ui.png)
+
+## File uploads
+
+Uploads are possible only if both Upload Attachment permission is granted to the user role and channel type Uploads configuration is enabled.
+
+## Poll creation
+
+:::note
+Polls feature is available in the React SDK as of version 12.5.0
+:::
+
+Poll creation is enabled only if both Create Poll permission is granted to the user role and channel type Polls configuration is enabled. Poll creation is not possible withing threads.
+
+### Poll creation UI
+
+The component in charge of rendering [the poll creation UI is `PollCreationDialog`](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Poll/PollCreationDialog/PollCreationDialog.tsx). The component is rendered in a modal and therefore accepts a prop `close`.
+
+![](../../assets/poll-creation-dialog.png)
+
+Custom `PollCreationDialog` can be provided via `Channel` prop `PollCreationDialog`:
+
+```tsx
+import { ReactNode } from 'react';
+import { Channel } from 'stream-chat-react';
+import type { PollCreationDialogProps } from 'stream-chat-react';
+
+const CustomPollCreationDialog = ({ close }: PollCreationDialogProps) => (
+
Custom Poll Creation Dialog
+);
+
+const ChannelWrapper = ({ children }: { children: ReactNode }) => (
+ {children}
+);
+```
+
+Created poll is then rendered within a message list by [`Poll` component](../../message-components/poll).
+
+## Attachment selector customization
+
+### Custom attachment selector actions
+
+Items in the `AttachementSelector` menu can be customized via its `attachmentSelectorActionSet` prop:
+
+```tsx
+import { ReactNode } from 'react';
+import { AttachmentSelector, Channel, defaultAttachmentSelectorActionSet } from 'stream-chat-react';
+import type {
+ AttachmentSelectorAction,
+ AttachmentSelectorActionProps,
+ AttachmentSelectorModalContentProps,
+} from 'stream-chat-react';
+
+// Define the menu button
+const AddLocationAttachmentAction = ({
+ closeMenu,
+ openModalForAction,
+}: AttachmentSelectorActionProps) => (
+
+);
+
+// Define the modal contents to be rendered if AddLocationAttachmentAction button is clicked
+const AddLocationModalContent = ({ close }: AttachmentSelectorModalContentProps) => {
+ return
abc
;
+};
+
+// the custom action will be at the top of the menu
+const attachmentSelectorActionSet: AttachmentSelectorAction[] = [
+ {
+ ActionButton: AddLocationAttachmentAction,
+ ModalContent: AddLocationModalContent,
+ type: 'addLocation',
+ },
+ ...defaultAttachmentSelectorActionSet,
+];
+
+const CustomAttachmentSelector = () => (
+
+);
+
+const ChannelWrapper = ({ children }: { children: ReactNode }) => (
+ {children}
+);
+```
+
+### Custom modal portal destination
+
+By default, the modals invoked by clicking on AttachmentSelector menu buttons are anchored to the channel container `div` element. The destination element can be changed by providing `getModalPortalDestination` prop to `AttachmentSelector`. This would be function that would return a reference to the target element that would serve as a parent for the modal.
+
+```tsx
+const getModalPortalDestination = () => document.querySelector('#my-element-id');
+
+const CustomAttachmentSelector = () => (
+
+);
+```
diff --git a/docusaurus/sidebars-react.json b/docusaurus/sidebars-react.json
index 87c847d2f..3563799b1 100644
--- a/docusaurus/sidebars-react.json
+++ b/docusaurus/sidebars-react.json
@@ -59,6 +59,7 @@
"components/message-components/ui-components",
"components/utility-components/avatar",
"components/utility-components/base-image",
+ "components/message-components/poll",
{
"Attachment": [
"components/message-components/attachment",
@@ -78,6 +79,7 @@
"components/message-input-components/ui_components",
"components/message-input-components/emoji-picker",
"components/message-input-components/audio_recorder",
+ "components/message-input-components/attachment-selector",
"components/contexts/typing_context"
]
},
diff --git a/src/components/Poll/PollContent.tsx b/src/components/Poll/PollContent.tsx
index 7d1cc35d2..96100a2fa 100644
--- a/src/components/Poll/PollContent.tsx
+++ b/src/components/Poll/PollContent.tsx
@@ -1,13 +1,13 @@
-import type { DefaultStreamChatGenerics } from '../../types';
-import type { PollState } from '../../../../stream-chat-js';
-import { PollHeader as DefaulPollHeader } from './PollHeader';
-import { PollActions as DefaultPollActions } from './PollActions';
-import { useComponentContext, usePollContext } from '../../context';
-import { useStateStore } from '../../store';
import clsx from 'clsx';
+import React from 'react';
+import { PollHeader as DefaultPollHeader } from './PollHeader';
+import { PollActions as DefaultPollActions } from './PollActions';
import { PollOptionList } from './PollOptionList';
import { MAX_OPTIONS_DISPLAYED } from './constants';
-import React from 'react';
+import { useComponentContext, usePollContext } from '../../context';
+import { useStateStore } from '../../store';
+import type { PollState } from 'stream-chat';
+import type { DefaultStreamChatGenerics } from '../../types';
type PollStateSelectorPollContentReturnValue = { is_closed: boolean | undefined };
const pollStateSelectorPollContent = <
@@ -19,7 +19,7 @@ export const PollContent = <
StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics
>() => {
const {
- PollHeader = DefaulPollHeader,
+ PollHeader = DefaultPollHeader,
PollActions = DefaultPollActions,
} = useComponentContext();
const { poll } = usePollContext();