Changelog
betaA list of product releases for a changelog page, newest first: each with its date and version, a title, a short summary, an optional cover, and its changes marked New, Improved, Fixed, or Removed.
Built from Badge, Button, Glide Highlight, Panel Switch, and Tabs.
Preview
- Version 3.11
Shared views
Save a filtered view of any list and share it with your team. Everyone sees the same columns and order.
- Save any filter as a view, and pin it to the sidebar.
- Share a view with a link. People without access see a request page.
- Column widths stay put when you switch views.
- Sorting by date no longer puts empty dates first.
- Version 3.10
Faster search
Search now answers as you type, across every workspace you belong to.
- Results show as you type.
- Search across every workspace from one box.
- Searching for a word with an accent finds it without the accent too.
- Version 3.9
API keys per project
Make a key that only reaches one project, and see when each key was last used.
- Keys that reach only one project.
- Each key shows when it was last used.
- Keys with no project. Move them to a project by December 1.
one release, no cover
- Version 1.0
The first release
Lists, comments, and sharing, on the web and on phones.
- Lists you can share with a link.
- Comments on every item.
long title and words
- Version 0.9.12-beta.3
Permissions for shared workspaces, guests, and outside reviewers across every project
Give each person exactly the access they need, from a single page, and see who can reach what at a glance.
- File names like annual-planning-notes-for-every-team-and-every-office-final.pdf now wrap instead of running out of the row.
- A guest who leaves a workspace loses access to its files at once, instead of at the next sign in.
no version: an id of your own, for #spring-update
Spring update
- Pages load faster on slow networks.
- Printing a list keeps its columns.
narrow container: the date sits above each release
- Version 0.8
Phone app
Everything from the web, on iPhone and Android.
- Apps for iPhone and Android.
- Version 0.7
Offline lists
- Lists open with no network, and sync when you are back.
- Edits made offline no longer show twice.
no releases yet
No releases yet.
Install
1. Add the registry to
components.json, once per app. Without it, the shadcn CLI looks up@txbrendanin a public list that txbrendan/ui does not control.npx shadcn@latest registry add "@txbrendan=https://txbrendan.dev/r/{name}.json"2. Add the theme, once per app. It replaces your color tokens with ones checked for contrast.
npx shadcn@latest add @txbrendan/theme3. Add the website component. It also adds every component it uses. Its own files go in your
componentsfolder, and they are yours to edit.npx shadcn@latest add @txbrendan/changelog
Use it for
- The body of a changelog page, under a Headline as the page's h1. Each release title is an h2.
- Pass `releases` newest first. Write each `date` as an ISO date, like "2026-10-28". It shows in words, like "October 28, 2026", the same on the server and in every browser.
- Give a release a `version`, like "2.4", and it gets the id "2-4", so a link to /changelog#2-4 lands on it. With no version, pass an `id` of your own. Keep every id unique on the page.
- A link to a release that is hidden, past the limit or out of the filter, still lands: the list shows it at once, then scrolls to it.
- Mark each change with a `type`: "new" is green, "removed" is red, and "improved" and "fixed" stay gray, so the news stands out.
- Set `limit` for a long list. It shows that many, then a Show older releases button that shows the rest in place and moves focus to the first one it showed.
- Set `filter` to add tabs for each type of change in your releases. A tab shows only the releases with that type, and only those changes.
- Pass a `cover` for a release worth a picture, like a drawing from our illustrations or a screenshot. It fills a 16:9 frame.
- The dates stick below a floating navbar as you read, and a link scrolls each release to the same place. Both read `--changelog-offset`, 6rem by default. Set it in `className`, like `[--changelog-offset:1rem]`, when nothing floats over the page.
Avoid it for
- An in-app feed of who did what, or the day's running order. Use Timeline, which keeps each item to one line on a rail.
- Live updates or alerts inside an app. Use a Toast or an Alert.
- Every commit or ticket. Group them into releases people can read, a few changes each.
- Long change lines. Keep each to one sentence, and put the detail in the summary or a page of its own.
Props
- releases
The releases, newest first. date is an ISO date. version also gives the release its id, "2.4" as "2-4", unless you pass id. cover fills a 16:9 frame. Each change has a type and its words. With none, it says there are no releases yet.
{ date: string; version?: string; id?: string; title: ReactNode; summary?: ReactNode; cover?: ReactNode; changes?: { type: "new" | "improved" | "fixed" | "removed"; text: ReactNode }[] }[] · default []
- limit
Shows this many first, then a Show older releases button that shows the rest. With none, every release shows.
number
- filter
Adds tabs over the list, All and one per type of change your releases have. It needs two types or more.
boolean · default false
- locale
The language the dates are written in, like "en-GB" or "de-DE".
string · default "en-US"
- className
Extra classes on the root, which holds the container query. The date column sits beside each release from 48rem of its own width, and above it when narrower. Set --changelog-offset here.
string
- ChangelogRelease
Type. One release.
{ date: string; version?: string; id?: string; title: ReactNode; summary?: ReactNode; cover?: ReactNode; changes?: ChangelogChange[] }
- ChangelogChange
Type. One change in a release.
{ type: "new" | "improved" | "fixed" | "removed"; text: ReactNode }
| Prop | Type | Default | What it does |
|---|---|---|---|
| releases | { date: string; version?: string; id?: string; title: ReactNode; summary?: ReactNode; cover?: ReactNode; changes?: { type: "new" | "improved" | "fixed" | "removed"; text: ReactNode }[] }[] | [] | The releases, newest first. date is an ISO date. version also gives the release its id, "2.4" as "2-4", unless you pass id. cover fills a 16:9 frame. Each change has a type and its words. With none, it says there are no releases yet. |
| limit | number | - | Shows this many first, then a Show older releases button that shows the rest. With none, every release shows. |
| filter | boolean | false | Adds tabs over the list, All and one per type of change your releases have. It needs two types or more. |
| locale | string | "en-US" | The language the dates are written in, like "en-GB" or "de-DE". |
| className | string | - | Extra classes on the root, which holds the container query. The date column sits beside each release from 48rem of its own width, and above it when narrower. Set --changelog-offset here. |
| ChangelogRelease | { date: string; version?: string; id?: string; title: ReactNode; summary?: ReactNode; cover?: ReactNode; changes?: ChangelogChange[] } | - | Type. One release. |
| ChangelogChange | { type: "new" | "improved" | "fixed" | "removed"; text: ReactNode } | - | Type. One change in a release. |
Accessibility
- The releases are an ordered list, newest first. Each is an article named by its title, an h2, so put the list under the page's h1.
- Each date is a <time> with the ISO date in dateTime.
- Each change's type is written on its badge, so it never rests on color alone.
- The tabs are named "Type of change". Arrow keys move between them. When the list changes, screen readers hear how many releases are left.
- Show older releases is a real button. Once pressed, it goes away and focus moves to the first release it showed, which sits where the button was.
- The hover fill is for the pointer only. Nothing in a release takes focus by itself.
- Reduced motion keeps the fades and drops the slides and the height glide.
- In forced colors each cover keeps a border, since its fill is painted away.
Examples
Releases with versions, covers, and changes
<Changelog
releases={[
{
date: "2026-10-28",
version: "2.4",
title: "Shared views",
summary: "Save a filtered view of any list and share it with your team.",
cover: <ThemeLayers />,
changes: [
{ type: "new", text: "Save any filter as a view." },
{ type: "improved", text: "Column widths stay put when you switch views." },
{ type: "fixed", text: "Sorting by date no longer puts empty dates first." },
],
},
{
date: "2026-10-14",
version: "2.3",
title: "Faster search",
changes: [{ type: "improved", text: "Results show as you type." }],
},
]}
/>A long list that starts short, with tabs for each type of change
<Changelog releases={releases} limit={5} filter />A changelog page under a floating navbar
<Navbar floating {...navbar} />
<main className="mx-auto flex max-w-7xl flex-col gap-16 px-4 pt-12">
<Headline as="h1" align="start" title="Changelog" description="New features, improvements, and fixes." />
<Changelog releases={releases} limit={5} filter />
</main>Dates in British English, with nothing floating over the page
<Changelog releases={releases} locale="en-GB" className="[--changelog-offset:1rem]" />