Activity Feed
blockproductivityRecord activity as a Timeline of avatar rows. Each row is spelled out inline — actor, verb, optional comment, relative time. Edit the rows after install; no items wrapper.
Installation
$pnpm dlx shadcn@latest add https://uipkge.dev/r/lit/activity-feed.json$npx shadcn@latest add https://uipkge.dev/r/lit/activity-feed.json$yarn dlx shadcn@latest add https://uipkge.dev/r/lit/activity-feed.json$bunx shadcn@latest add https://uipkge.dev/r/lit/activity-feed.jsonManifest:
https://uipkge.dev/r/lit/activity-feed.jsonInstalls to:src/uip/blocks/activity-feed/Variants
Loading interactive previews…
Loading interactive previews…
Schema
Type aliases exported from this item's source. Use these to shape the data you pass in.
HTMLElementTagNameMapinterface HTMLElementTagNameMap {
'uip-activity-feed': UipActivityFeed
}
}npm dependencies
Files installed (1)
src/uip/blocks/activity-feed/activity-feed.ts5.1 kB
import { LitElement, css, html } from 'lit' import { tailwind } from '../../lib/styles' import { ThemeController } from '../../lib/theme' // Side-effect imports: register the composed elements for standalone use // (consumers who install only this block still get working primitives). import '../../components/avatar/avatar' import '../../components/relative-time/relative-time' import '../../components/section-card/section-card' import '../../components/timeline/timeline' /** * <uip-activity-feed> — the registry ActivityFeed block as a web component. * * Class strings are React's ActivityFeed verbatim. Every row is spelled out * inline as in React (actor, verb, optional comment, relative time) — no * items wrapper, per the block boundary rules. Timestamps are pinned to the * same fixed `now` as React so the relative labels match the demo. */ export class UipActivityFeed extends LitElement { static shadowRootOptions = { ...LitElement.shadowRootOptions, delegatesFocus: true } // :host display can't be a utility class (the host has no template of its own). static styles = [tailwind, css`:host { display: block; }`] constructor() { super() new ThemeController(this) } connectedCallback() { super.connectedCallback() this.setAttribute('data-uipkge', '') this.setAttribute('data-slot', 'activity-feed') } render() { const now = '2026-08-14T12:00:00.000Z' return html` <uip-section-card data-slot="activity-feed" heading="Activity" description="Latest changes on this record."> <uip-timeline> <uip-timeline-item status="success"> <uip-timeline-media variant="avatar"> <uip-avatar size="sm"> <uip-avatar-fallback size="sm" class="text-foreground">MC</uip-avatar-fallback> </uip-avatar> </uip-timeline-media> <uip-timeline-content> <p class="text-sm"> <span class="font-medium">Maya Chen</span> <span class="text-muted-foreground"> approved the leave request</span> </p> <uip-relative-time date="2026-08-14T11:18:00.000Z" now=${now} locale="en" class="mt-0.5 block text-xs" ></uip-relative-time> </uip-timeline-content> </uip-timeline-item> <uip-timeline-item status="info"> <uip-timeline-media variant="avatar"> <uip-avatar size="sm"> <uip-avatar-fallback size="sm" class="text-foreground">OF</uip-avatar-fallback> </uip-avatar> </uip-timeline-media> <uip-timeline-content> <p class="text-sm"> <span class="font-medium">Omar Farid</span> <span class="text-muted-foreground"> added a comment</span> </p> <p class="text-muted-foreground mt-1 text-sm">Coverage is confirmed for Thursday and Friday.</p> <uip-relative-time date="2026-08-14T10:04:00.000Z" now=${now} locale="en" class="mt-0.5 block text-xs" ></uip-relative-time> </uip-timeline-content> </uip-timeline-item> <uip-timeline-item status="muted"> <uip-timeline-media variant="avatar"> <uip-avatar size="sm"> <uip-avatar-fallback size="sm" class="text-foreground">PS</uip-avatar-fallback> </uip-avatar> </uip-timeline-media> <uip-timeline-content> <p class="text-sm"> <span class="font-medium">Priya Shah</span> <span class="text-muted-foreground"> updated the title to “Q3 planning offsite”</span> </p> <uip-relative-time date="2026-08-13T16:40:00.000Z" now=${now} locale="en" class="mt-0.5 block text-xs" ></uip-relative-time> </uip-timeline-content> </uip-timeline-item> <uip-timeline-item status="muted"> <uip-timeline-media variant="avatar"> <uip-avatar size="sm"> <uip-avatar-fallback size="sm" class="text-foreground">LP</uip-avatar-fallback> </uip-avatar> </uip-timeline-media> <uip-timeline-content> <p class="text-sm"> <span class="font-medium">Leo Park</span> <span class="text-muted-foreground"> opened this request</span> </p> <uip-relative-time date="2026-08-13T09:12:00.000Z" now=${now} locale="en" class="mt-0.5 block text-xs" ></uip-relative-time> </uip-timeline-content> </uip-timeline-item> </uip-timeline> </uip-section-card> ` } } customElements.get('uip-activity-feed') || customElements.define('uip-activity-feed', UipActivityFeed) declare global { interface HTMLElementTagNameMap { 'uip-activity-feed': UipActivityFeed } }
Raw manifest:https://uipkge.dev/r/lit/activity-feed.json