Activity Feed

Pro

A vertical timeline of what happened: comments, mentions, status changes, uploads, members joining. One rail threads every event, while each row varies its marker and its body, from a terse audit log to a rich inbox.

  1. S
    Sarah Chencommented
    Love the new onboarding flow. The empty states make a huge difference. Can we ship the copy tweaks before Friday?
  2. Marcus Leementioned you in Q3 roadmap
    “@you can you own the migration checklist for this one?”
  3. Priya Nairuploaded 2 files
    Brand gradient exploration
    Brand-guidelines.pdf
    2.4 MB · PDF document
  4. Marcus Leechanged status toDone
  5. Sarah Chenreacted to your comment
  6. Priya Nairchanged the due date to Jun 20

A workflow at a glance#

An episode moves from interview review to release in a series of small handoffs. Activity Feed keeps the full sequence readable; a compact phase bar makes the total production time easy to scan.

The quiet art of starting over

Episode 024 · Northbound

Scheduled
  1. Review interview
  2. Edit conversation
  3. Mix and master
  4. Generate transcript
  5. Schedule episode
Episode scheduled for Friday, 09:00

Production overview

A 42-minute conversation, ready to go

workflow · 55mepisode 024
Prepare12mProduction37mPublish6m
Review interview12m00:00
Edit conversation28m00:12
Mix and master9m00:40
Generate transcript4m00:49
Schedule episode2m00:53
Ready to publish

55min

1,842-word transcript

Installation#

# One-time setup (tokens + lib helpers)npx koalaui-cli@latest init# Activate your Pro license (once per machine)npx koalaui-cli@latest login <key># Add this component (its dependencies come along)npx koalaui-cli@latest add activity-feed

Usage#

Activity Feed is composed from named parts, like Ranking. The ActivityFeed root is a semantic <ol> that owns density and the connecting rail; each ActivityItem pairs an ActivityMarker (drop an ActivityIcon, an Avatar, or an ActivityDot inside it) with an ActivityContent body. The rail is drawn automatically and closes itself on the last event.

This example is part of Koala UI Pro

The preview is yours to explore. Its code comes with a Pro license, paid once and used in every project.

Have a license? Unlock it here

  1. Alex Riveraopened the issue
  2. Alex Riveramerged the pull request

Anatomy#

import {  ActivityFeed,  ActivityGroup,  ActivityGroupLabel,  ActivityItem,  ActivityMarker,  ActivityIcon,  ActivityContent,  ActivityHeader,  ActivityActor,  ActivityTime,  ActivityBody,  ActivityCard,  ActivityAttachments,  ActivityImage,  ActivityActions,} from "@/components/ui/activity-feed"<ActivityFeed>  <ActivityGroup>    <ActivityGroupLabel />    <ActivityItem>      <ActivityMarker>        <ActivityIcon />      </ActivityMarker>      <ActivityContent>        <ActivityHeader>          <ActivityActor />          <ActivityTime />        </ActivityHeader>        <ActivityBody />        <ActivityCard />        <ActivityAttachments>          <ActivityImage />        </ActivityAttachments>      </ActivityContent>      <ActivityActions />    </ActivityItem>  </ActivityGroup></ActivityFeed>

Playground#

Flip the knobs and watch the snippet keep up. Note that the two groups do different things: Props are values the component takes, while Parts are children you compose in or leave out, which is why turning one off removes an element from the code rather than adding a show-something prop. Turn them all off and the event still holds its alignment.

  1. Marcus Leementioned you in Q3 roadmap
  2. Priya Nairuploaded the press kit
  3. Sarah Chenclosed the milestone
Playground
Props

Cross-cutting spacing axis.

What separates one event from the next.

Applied to the first event here.

Hover, press and focus affordance.

Parts

An icon, an Avatar, or a dot.

The relative timestamp.

A muted one-liner under the header.

Trailing controls for the row.

This example is part of Koala UI Pro

The preview is yours to explore. Its code comes with a Pro license, paid once and used in every project.

Have a license? Unlock it here

Only the parts you need#

There is no showTime or showBody prop, because there is nothing to switch off: an event is whatever parts you put in it. Every part is droppable, and whichever one leads the content takes over the alignment, so a header-only event, a body-only event, and a card-only event all sit on the same axis as their marker.

header only

  1. Dana Wucommented

body only

  1. Reopened after the staging deploy went out.

card only

  1. Can we ship the copy tweaks before Friday?

Markers#

The marker carries the type of event. ActivityIcon is a soft tinted tile: pass a Koala glyph and a tone (brand, success, info, destructive, purple, and more). For people, drop an Avatar in the same slot; for minor events, ActivityDot is a low-emphasis dot. All three share a 32px footprint, so the rail stays aligned whichever you use.

  1. J
    June Parkjoined the workspace
  2. June Parkwas assigned to Billing v2
  3. June Parkrenamed the project

Attachments#

Events carry payloads, and the feed composes them from existing components rather than re-rolling chips. Stack them in ActivityAttachments: drop a File Card row in for each file (it already ships the type-tinted icon, name, and meta) and lay ActivityImage thumbnails out in a flex flex-wrap row for an image gallery. For an upload-in-progress state, use File Card’s FileCardProgress; to collect the files in the first place, see File Upload.

  1. Priya Nairattached 3 files
    Poster concept
    Color study
    source-assets.zip
    18 MB · Archive

Quoted comments#

ActivityCard is a nested surface for quoted content: a posted comment, a review, a changelog note. Its radius steps down concentrically from the Card the feed usually sits in. For a short, muted one-liner under the header, use ActivityBody instead.

  1. D
    Dana Wuleft a review
    The motion polish is great, but the empty-state illustration feels a touch heavy against the cream theme. Maybe drop it to 80% opacity?

Unread#

Mark an event as new to this reader with unread on ActivityItem: the header comes up to full-strength text and an ink dot rides the end of the row (with a screen-reader label). Deliberately no tinted row fill, since a feed is chrome-less and a band would read as a container.

  1. Marcus Leementioned you in Q3 roadmap
    Unread
  2. Billing v2is ready for review
    Unread
  3. Sarah Chenclosed the milestone

Interactive events#

Pass asChild with an <a> child to make a whole event a link: the <li> stays the list item while the child becomes the hover-lit surface, so the markup is valid <li><a>. Use interactive on its own for a row that takes an onClick. The press feedback deepens the fill rather than scaling the row, the same call List makes for flush rows.

Row actions#

ActivityActions is a trailing slot for per-event controls: a reply, a download, an overflow menu. It sits beside ActivityContent rather than inside the header (which wraps), and parks on the marker’s axis so it rides the first line however tall the event grows. Don’t combine it with asChild, which would nest a control inside a link.

  1. S
    Sarah Chencommented
    The motion polish landed nicely. One nit: the rail still reads a touch dark on cream.
  2. Priya Nairuploaded a file
    Brand-guidelines.pdf
    2.4 MB · PDF document

Day groups#

ActivityGroup gathers a run of events under a heading, a day or any other bucket, with an ActivityGroupLabel first. The label sits in the events' text column and the rail runs straight past it, so the timeline stays one line from the first event to the last. Each group is its own list, named by its label for a screen reader (“Today, list, 2 items”). The label is droppable, and a divided feed or one without the rail groups the same way.

    1. S
      Sarah Chenchecked in for the 10:30 visit
    2. Front deskmarked the invoice paid
    1. Marcus Leeleft a note on the record
      Prefers morning slots, bring the X-ray from March.
    2. Sarah Chenbooked a visit

Divided#

divided swaps the vertical rail for a hairline rule between events: the audit-log and notification-inbox reading. It re-balances the per-event rhythm so each rule sits evenly between its neighbours, and it takes the rail with it. A rule and a rail are two answers to the same question, so a divided feed never draws the connector and connector is ignored there.

  1. June Parkedited the brief
  2. June Parkuploaded the press kit
  3. June Parkrenamed the project

Without the rail#

Set connector={false} on the feed for a plain list of events with no connecting line, useful for a single notification, a digest, or a card where the timeline framing would be too heavy.

  1. D
    Dana Wuleft a review
    The motion polish is great, but the empty-state illustration feels a touch heavy against the cream theme. Maybe drop it to 80% opacity?

Density#

Density is Koala’s cross-cutting spacing axis (see Density). For the feed it tunes the gap to the rail and each event’s own padding; the marker size stays fixed so the rail aligns identically at both densities. compact is the default; comfortable opens it up for a roomier inbox. Set it per-feed or for a whole subtree with DensityProvider.

comfortable

  1. Alexedited the brief
  2. Alexexported the report

compact

  1. Alexedited the brief
  2. Alexexported the report

API reference#

ActivityFeed

The root, a semantic <ol> that owns density and the connecting rail. Forwards all native <ol> props. Every part accepts className, merged last.

PropTypeDefaultDescription
density"comfortable" | "compact""compact"Per-event rhythm and the gap to the rail. Falls back to the nearest DensityProvider, then compact.
dividedbooleanfalseA hairline rule between events instead of the rail (the audit-log reading).
connectorbooleantrueDraws the vertical rail between markers. Ignored when divided is set.

ActivityGroup

A run of events under one heading, such as a day. Renders an <li> of the feed holding its own <ol>, named by its label. Forwards all native <li> props.

ActivityGroupLabel

The small heading of a group ("Today"), first in the group and droppable. Renders an <li> that becomes the accessible name of the group's list. Forwards all native <li> props.

ActivityItem

One event, an <li>. Forwards all native <li> props.

PropTypeDefaultDescription
asChildbooleanfalseRenders the row as its single child (an <a> or <button>) inside the <li>. Implies interactive; do not pair with ActivityActions.
interactivebooleanfalseAdds the hover fill, press and focus ring. Defaults to true when asChild is set.
unreadbooleanfalseMarks the event as new: full-strength header text plus an ink dot (and an sr-only "Unread").

ActivityMarker

The rail column. Holds an ActivityIcon, ActivityDot or Avatar and appends the rail itself, closed on the last event. Forwards all native <div> props.

ActivityIcon

A 28px tinted tile marker. Pass a Koala glyph as children. Forwards all native <div> props.

PropTypeDefaultDescription
tone"default" | "brand" | "success" | "warning" | "info" | "destructive" | "purple" | "pink" | "teal" | "orange""default"The soft tint, matched to the kind of event.

ActivityDot

A low-emphasis dot marker for minor events, in the same footprint as ActivityIcon. Forwards all native <div> props.

PropTypeDefaultDescription
tone"default" | "brand" | "success" | "warning" | "info" | "destructive" | "purple" | "pink" | "teal" | "orange""default"The solid color of the dot.

ActivityContent

The text column of an event. Forwards all native <div> props.

ActivityHeader

The wrapping first line: actor, verb, target, time. Forwards all native <div> props.

ActivityActor

The person or thing that acted, a <span>. Forwards all native <span> props.

PropTypeDefaultDescription
asChildbooleanfalseRenders the actor as its child element, such as a profile link.

ActivityTime

The muted, tabular timestamp, a real <time>. Pass an ISO dateTime and a relative label as children. Forwards all native <time> props.

ActivityBody

Secondary text under the header. Forwards all native <div> props.

ActivityCard

A nested surface for quoted content (a comment, a review), on the concentric radius. Forwards all native <div> props.

ActivityAttachments

A vertical stack for the payload: FileCard rows and ActivityImage rows. Forwards all native <div> props.

ActivityImage

A 56px image thumbnail with the image-outline ring. className sizes the clipping wrapper; every other prop goes to the native <img>.

PropTypeDefaultDescription
alt*string-The image's alternative text.

ActivityActions

Trailing controls for one event, a sibling of ActivityContent that rides the first line. Forwards all native <div> props.

FAQ#

Use `ActivityIcon` with a tone for typed events (a status change, an upload), an `Avatar` when a specific person acted, and `ActivityDot` for low-emphasis minor events like a field edit. All three share a fixed footprint inside `ActivityMarker`, so the rail stays aligned whichever you pick.