Activity Feed
A flexible chronological feed for product activity, audit events, notifications, and collaboration history.
ActivityFeed displays a chronological stream of events. It is useful for audit logs, issue history, collaboration updates, deployment events, notifications, and any other sequence where each entry has an actor, time, status, or supporting content.
It provides the visual language of a timeline with richer event content: avatars and icons, unread state, metadata, actions, links, grouping, expandable details, loading and empty states, controlled active state, and custom React content.
Basic usage
import { ActivityFeed } from '@mosmox/ui';
<ActivityFeed
aria-label="Project activity"
items={[
{
key: 'deploy-1',
title: 'Production deployment completed',
actor: 'Maya Chen',
timestamp: '10 minutes ago',
description: 'Version 2.4.0 is now available to customers.',
status: 'success',
},
{
key: 'comment-1',
title: 'Commented on the checkout task',
actor: 'Noah Williams',
timestamp: '1 hour ago',
unread: true,
status: 'default',
},
]}
/>;Each item needs a unique key and title. All other fields are optional.
Rich activity items
An item can combine an actor, avatar, icon, description, metadata, custom content, an external link, and actions:
<ActivityFeed
items={[
{
key: 'review',
title: 'Pull request approved',
actor: 'Alex Morgan',
avatar: <img alt="Alex Morgan" src="/avatars/alex.jpg" />,
timestamp: 'Today, 14:32',
status: 'success',
metadata: <span>payments-api · PR #184</span>,
content: <strong>Ready to merge</strong>,
href: '/pull-requests/184',
actions: <button type="button">Open review</button>,
},
]}
/>;avatar and icon replace the default status marker. Use avatar for people and icon for a product-specific event. metadata, content, and actions accept any React content. When href is present, the title becomes a link.
The marker priority is avatar, then icon, then the status icon. Use a decorative avatar only when the actor is also provided as text; the marker itself is hidden from assistive technology.
Status, unread, and disabled states
status accepts default, pending, success, warning, or danger. The status changes the marker and accent without requiring custom CSS. Set unread to highlight new activity and disabled to make an event visually inactive and non-interactive.
<ActivityFeed
items={[
{ key: 'queued', title: 'Build queued', status: 'pending' },
{ key: 'warning', title: 'Environment variable is missing', status: 'warning', unread: true },
{ key: 'failed', title: 'Deployment failed', status: 'danger', disabled: true },
]}
/>;Grouping and ordering
Give items a group label and enable showGroups to render sections such as Today, Yesterday, or a date. reverse displays the supplied items from newest to oldest without mutating the original array.
<ActivityFeed
showGroups
reverse
items={[
{ key: 'a', group: 'Today', title: 'Published a release' },
{ key: 'b', group: 'Yesterday', title: 'Updated the roadmap' },
]}
/>;Active item and item clicks
Pass onItemClick to make items keyboard and pointer interactive. The callback receives the item and its zero-based index. Use defaultActiveKey for an uncontrolled feed or activeKey with onActiveChange for controlled state.
const [activeKey, setActiveKey] = useState('deploy');
<ActivityFeed
activeKey={activeKey}
onActiveChange={(key) => setActiveKey(key)}
onItemClick={(item) => console.log('Selected:', item.key)}
items={items}
/>;Interactive items expose button-like keyboard behavior: Enter and Space activate the item. Actions stop propagation so an action inside an item does not also select the event.
Without onItemClick, items are read-only. activeKey is controlled state; defaultActiveKey is used only for the initial uncontrolled state. onActiveChange receives both the new key and the complete item.
Expandable details
Set collapsible and provide details on an item to add a “View details” control. Expansion can be uncontrolled with defaultExpandedKeys, or controlled with expandedKeys and onExpandedChange.
<ActivityFeed
collapsible
defaultExpandedKeys={['deploy']}
onExpandedChange={(keys, item) => console.log(keys, item)}
items={[
{
key: 'deploy',
title: 'Deployment completed',
details: <pre>{'Build: 8f31c2\nRegion: eu-central-1'}</pre>,
},
]}
/>;Variants, sizes, and layout
variant:default,compact,bordered, orcard.size:sm,default, orlg.showConnector: shows the vertical event connector; enabled by default.maxHeight: number of pixels or any CSS height value; enables a scrollable feed.classNameandstyle: add local styling without changing the component contract.
The default feed uses 14px horizontal and 8px vertical content padding. The sm size uses 10px horizontal and 6px vertical padding. These values can be changed globally with ConfigProvider.
<ActivityFeed
size="sm"
variant="card"
showConnector={false}
maxHeight={360}
items={items}
/>;Loading and empty states
Use loading while events are being fetched. When items is empty, emptyState replaces the list and accepts any React content.
<ActivityFeed
loading={isLoading}
emptyState={<span>No activity has been recorded yet.</span>}
items={events}
/>;Custom composition
Use children when the event data is already rendered or when an application needs a custom composition. The supplied children replace the generated item list, while the feed container still provides the selected variant, size, connector, and layout classes.
<ActivityFeed variant="bordered" aria-label="Custom activity">
<article>Custom event content</article>
</ActivityFeed>ConfigProvider defaults
Configure defaults once for an application or design-system surface. Individual props override provider defaults.
<ConfigProvider
components={{
activityFeed: {
size: 'sm',
variant: 'card',
showConnector: false,
horizontalPadding: 12,
verticalPadding: 8,
},
}}
>
<ActivityFeed items={items} />
</ConfigProvider>ActivityFeedConfig supports the following provider defaults:
| Property | Type | Default | Description |
|---|---|---|---|
size | 'sm' | 'default' | 'lg' | 'default' | Feed density and marker sizing. |
variant | 'default' | 'compact' | 'bordered' | 'card' | 'default' | Visual treatment. |
showConnector | boolean | true | Shows the vertical connector rail. |
horizontalPadding | number | string | 14px (10px for sm) | Horizontal inset for event content and timestamp. |
verticalPadding | number | string | 8px (6px for sm) | Vertical inset around each event's hover surface. |
Accessibility
- The root is a labelled
section; providearia-labelwhen more than one feed is present. - Every item title is rendered as a heading for readable event structure.
- Interactive items support
EnterandSpaceand expose the selected item witharia-current. - Native buttons remain native for details and action controls.
- Use meaningful
alttext for avatars and avoid putting essential information only in a decorative icon. - Loading skeletons are hidden from assistive technology; provide surrounding loading status in the application when necessary.
API reference
ActivityFeedItem
| Property | Type | Default | Description |
|---|---|---|---|
key | string | required | Unique event identifier. |
title | ReactNode | required | Event title, rendered as a heading. |
description | ReactNode | — | Supporting event description. |
timestamp | ReactNode | — | Human-readable time or formatted date. |
actor | ReactNode | — | Person or system responsible for the event. |
avatar | ReactNode | — | Avatar content used as the marker. |
icon | ReactNode | — | Custom event icon used as the marker. |
status | 'default' | 'pending' | 'success' | 'warning' | 'danger' | — | Marker and semantic accent state. |
metadata | ReactNode | — | Auxiliary labels, tags, or identifiers. |
content | ReactNode | — | Main custom event content. |
details | ReactNode | — | Expandable content when collapsible is enabled. |
actions | ReactNode | — | Action controls rendered below the event. |
group | ReactNode | — | Group heading used by showGroups. |
href | string | — | Link applied to the title. |
unread | boolean | false | Highlights the event as unread. |
disabled | boolean | false | Dims the event and prevents interaction. |
ActivityFeedProps
| Property | Type | Default | Description |
|---|---|---|---|
items | ActivityFeedItem[] | [] | Events to render. |
children | ReactNode | — | Custom content replacing the generated item list. |
size | 'sm' | 'default' | 'lg' | 'default' | Feed density and marker sizing. |
variant | 'default' | 'compact' | 'bordered' | 'card' | 'default' | Visual treatment. |
reverse | boolean | false | Renders a reversed copy of the supplied items. |
showConnector | boolean | true | Shows the vertical connector rail. |
showGroups | boolean | false | Renders headings from each item's group. |
collapsible | boolean | false | Enables details toggles for items with details. |
activeKey | string | — | Controlled active item key. |
defaultActiveKey | string | — | Initial active item key for uncontrolled state. |
onActiveChange | (key, item) => void | — | Called when the active item changes. |
expandedKeys | string[] | — | Controlled expanded detail keys. |
defaultExpandedKeys | string[] | [] | Initial expanded detail keys. |
onExpandedChange | (keys, item) => void | — | Called after detail expansion changes. |
onItemClick | (item, index) => void | — | Makes enabled items interactive and receives activation. |
loading | boolean | false | Shows loading skeletons instead of items. |
emptyState | ReactNode | 'No activity yet.' | Content shown when items is empty. |
maxHeight | number | string | — | Maximum feed height with scrolling. |
className | string | — | Custom root class. |
style | CSSProperties | — | Inline root styles. |
aria-label | string | 'Activity feed' | Accessible name for the feed section. |
horizontalPadding and verticalPadding are ConfigProvider component defaults, not per-instance ActivityFeed props. Use the style prop for one-off CSS customization.