Navigation
Feed
An infinite-scroll list of articles that keyboard users can page through and escape.
When to use it: Use it for scroll-loaded content such as news or activity streams; use GridList for a selectable collection.
Example
Roasted tomato soup
A weeknight classic, deepened with slow-roasted garlic.
Charred corn salad
Sweet corn, lime, and a little heat from pickled jalapeño.
Smoky bean stew
Pantry beans simmered with smoked paprika and greens.
import { Feed, FeedArticle } from "@comp0/react";
const stories = [
{
id: "feed-story-soup",
title: "Roasted tomato soup",
teaser: "A weeknight classic, deepened with slow-roasted garlic.",
},
{
id: "feed-story-salad",
title: "Charred corn salad",
teaser: "Sweet corn, lime, and a little heat from pickled jalapeño.",
},
{
id: "feed-story-stew",
title: "Smoky bean stew",
teaser: "Pantry beans simmered with smoked paprika and greens.",
},
];
export function Example() {
return (
<div className="flex w-full max-w-sm flex-col gap-2">
<button
type="button"
className="self-start rounded px-3 py-2.5 text-base text-teal-700 hover:bg-teal-50 sm:py-2 sm:text-sm dark:text-teal-300 dark:hover:bg-teal-950"
>
Refresh stories
</button>
<Feed aria-label="Recipe stories" total={12} className="flex flex-col gap-2">
{stories.map((story) => (
<FeedArticle
key={story.id}
aria-labelledby={story.id}
className="rounded border border-zinc-950/10 p-3 outline-teal-600 focus-visible:outline-2 dark:border-white/10 dark:outline-teal-400"
>
<h3
id={story.id}
className="text-base font-medium text-zinc-900 sm:text-sm dark:text-zinc-100"
>
{story.title}
</h3>
<p className="mt-1 text-base text-zinc-600 sm:text-sm dark:text-zinc-400">
{story.teaser}
</p>
</FeedArticle>
))}
</Feed>
<button
type="button"
className="self-start rounded px-3 py-2.5 text-base text-teal-700 hover:bg-teal-50 sm:py-2 sm:text-sm dark:text-teal-300 dark:hover:bg-teal-950"
>
Load older stories
</button>
</div>
);
}Anatomy
Dashed frames are invisible state providers; shaded shapes own real DOM. Numbered pins match the list below.
A wireframe sketch of the assembled component. Each numbered marker matches a part in the list that follows.
Feed
The scroll-loaded article list; PageDown and PageUp walk it and Ctrl+Home / Ctrl+End escape it. Owns a DOM element.
FeedArticle
Native article that can receive focus; announces its position and set size automatically. Owns a DOM element.
Step by step
- 1
Add the main part
Wrap the stream in Feed with an aria-label.
- 2
Add the supporting parts
Render one FeedArticle per story with aria-labelledby pointing at its title.
- 3
Make the behavior clear
Set busy while loading more, and total when you know how many articles exist beyond the rendered ones.
Exampletsx <Feed aria-label="Recipe stories" busy={loading}><FeedArticle aria-labelledby="story-1"><h3 id="story-1">Roasted tomato soup</h3></FeedArticle></Feed>
Keyboard
- PgDn
- Moves focus to the next article.
- PgUp
- Moves focus to the previous article.
- CtrlEnd
- Moves focus to the first focusable element after the feed.
- CtrlHome
- Moves focus to the first focusable element before the feed.
- ⇥
- Moves through links and controls inside the focused article.
Forms and accessibility
A feed does not create form values.
Accessibility checklist
- Give the feed an aria-label naming the stream, such as Recipe stories.
- Label every article via aria-labelledby on FeedArticle so PageDown announces where it landed.
- Keep something focusable before and after the feed; Ctrl+Home and Ctrl+End are how keyboard users escape an endless scroll.
API reference
import { Feed, FeedArticle } from "@comp0/react";Feed
DOM elementThe scroll-loaded article list; PageDown and PageUp walk it and Ctrl+Home / Ctrl+End escape it.
| Prop | Type | Description |
|---|---|---|
aria-label | string | Names the feed for assistive technology; required. |
busy | boolean | Marks the feed as loading more articles via aria-busy. |
total | number | Total article count when known beyond the rendered ones; feeds aria-setsize, which otherwise reports the rendered count. |
FeedArticle
DOM elementNative article that can receive focus; announces its position and set size automatically.
| Prop | Type | Description |
|---|---|---|
aria-labelledby | string | Point it at the article's title element so screen readers hear what it is about. |
Style hooks
Attributes that appear while a state is true. Target them with Tailwind data variants such as data-open:bg-zinc-100, or with any CSS selector.
[data-busy]on Feed
- More articles are loading.
:focus-visibleon FeedArticle
- The article has keyboard focus.