ChangelogView
MD · 1950B gzip budgetVersioned changelog with date grouping and category tags.
- Category
- Data display
- Budget
- md, several states or a live subscription
- External runtime
- React / React DOM only
axe fixtureSSR rendersource scanbundle budget
Preview
Live fixturev1.0.0
- addedInitial release
Try the component here. Locale-aware formatting and direction follow the selected language; example content and labels are not automatically translated. Overlay demos use interactive launchers.
Install
npx shadcn@latest add https://gear5-ui.vercel.app/r/changelog-view.jsonCopies the source into your project. Pulls in 1 shared registry item: cn.
New here? Set up Tailwind and import aliases first →Source & props
Edit on GitHub ↗Prop types and inline documentation are included below. This is repository source; the installer rewrites shared imports for your project.
import { cn } from "../lib/cn";
export interface ChangelogEntry {
version: string;
date: string;
changes: { type: "added" | "fixed" | "changed" | "removed"; description: string }[];
}
export interface ChangelogViewProps {
entries: ChangelogEntry[];
className?: string;
}
const TYPE_STYLES: Record<string, string> = {
added: "bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-300",
fixed: "bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300",
changed: "bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-300",
removed: "bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-300",
};
/**
* Changelog timeline with version tags. Each entry is an `<article>` with
* an `<h3>` for the version. Change type badges use `aria-label` to convey
* meaning beyond colour.
*/
export function ChangelogView({ entries, className }: ChangelogViewProps) {
return (
<div className={cn("flex flex-col gap-6", className)} role="feed" aria-label="Changelog">
{entries.map((entry) => (
<article key={entry.version} aria-label={`Version ${entry.version}`} className="relative ps-6">
<span
aria-hidden="true"
className="absolute start-0 top-1 size-3 rounded-full bg-blue-600"
/>
<div className="flex flex-col gap-2">
<div className="flex items-baseline gap-2">
<h3 className="text-lg font-bold text-neutral-900 dark:text-neutral-100">
v{entry.version}
</h3>
<time className="text-sm text-neutral-500 dark:text-neutral-400">{entry.date}</time>
</div>
<ul className="flex flex-col gap-1">
{entry.changes.map((change, index) => (
<li key={index} className="flex items-start gap-2 text-sm">
<span
aria-label={change.type}
className={cn(
"inline-flex shrink-0 items-center rounded-full px-2 py-0.5 text-xs font-medium capitalize",
TYPE_STYLES[change.type] ?? TYPE_STYLES.changed,
)}
>
{change.type}
</span>
<span className="text-neutral-700 dark:text-neutral-300">{change.description}</span>
</li>
))}
</ul>
</div>
</article>
))}
</div>
);
}
What CI checks
Quality contract- Bundled, minified and gzipped against its tier budget
- Audited by axe in the state previewed above
- Rendered through react-dom/server with no browser globals
- Scanned for network calls, dangerous sinks, and unguarded animation