# Activity Feed Group

Date-grouped section header for activity feeds.

## Installation

```bash
npx shadcn@latest add https://ui.uptoolkit.com/r/activity-feed-group.json
```

[Registry JSON](https://ui.uptoolkit.com/r/activity-feed-group.json)

## Preview

```tsx
import {
  toFeedEntries,
  sampleActivityCollection,
} from "@/lib/activity-entries";
import { getCollectionItems } from "@/lib/activitypub";
import { sampleViewer } from "@/lib/social-sample-data";
import { ActivityFeedItem } from "@/components/ui/activity-feed-item";
import { ActivityFeedGroup } from "@/components/ui/activity-feed-group";

const entries = toFeedEntries(getCollectionItems(sampleActivityCollection)).slice(0, 2);

export function Preview() {
  return (
    <ActivityFeedGroup label="Today">
      <ol className="m-0 flex list-none flex-col gap-3 p-0">
        {entries.map((entry) => (
          <li key={entry.activity.id}>
            <ActivityFeedItem entry={entry} viewer={sampleViewer} />
          </li>
        ))}
      </ol>
    </ActivityFeedGroup>
  );
}
```


## Source

### ui/activity-feed-group.tsx

```tsx
import * as React from "react";

import { Separator } from "@/components/ui/separator";
import { cn } from "@/lib/utils";

type ActivityFeedGroupProps = Omit<React.ComponentProps<"section">, "children"> & {
  /** Human-readable heading, for example "Today" or "March 2025". */
  label: string;
  children: React.ReactNode;
};

/**
 * Date-grouped section for an activity feed.
 *
 * Renders a muted uppercase heading with a trailing rule, then the entry list
 * passed as `children`. Pair with {@link ActivityFeedItem} inside an `<ol>`.
 */
function ActivityFeedGroup({ label, children, className, ...props }: ActivityFeedGroupProps) {
  return (
    <section aria-label={label} className={cn("flex flex-col gap-3", className)} {...props}>
      <div className="flex items-center gap-3">
        <h3 className="m-0 text-xs font-medium tracking-wide text-muted-foreground uppercase">
          {label}
        </h3>
        <Separator className="flex-1" />
      </div>
      {children}
    </section>
  );
}

export { ActivityFeedGroup, type ActivityFeedGroupProps };
```



## Usage

A muted uppercase heading with a trailing rule, wrapping a list of feed entries.
Use it inside [`activity-feed`](/blocks/activity-feed) or build your own grouped layout.

```tsx
import { ActivityFeedGroup } from "@/components/ui/activity-feed-group";
import { ActivityFeedItem } from "@/components/ui/activity-feed-item";

<ActivityFeedGroup label="Today">
  <ol className="m-0 flex list-none flex-col gap-3 p-0">
    {entries.map((entry) => (
      <li key={entry.activity.id}>
        <ActivityFeedItem entry={entry} viewer={viewer} />
      </li>
    ))}
  </ol>
</ActivityFeedGroup>;
```

The `label` becomes both the visible heading and the section's `aria-label`.

