shadcn.io is an independent project built on shadcn/ui
A commit shows up as one card: the message, the short hash, who made it and when. The files it changed open below, each with a letter for what happened to it and its line counts.
Use it when a coding agent commits during a chat, so the reader can see what changed without opening git. One edited file reads better as a Trace line, and the diff itself belongs in a Code Block. In React, Radix UI draws the card; the commit's data comes from you.
Installation
Anatomy

Commit
├── CommitHeader
│ ├── CommitAuthor
│ │ └── CommitAuthorAvatar
│ ├── CommitInfo
│ │ ├── CommitMessage
│ │ └── CommitMetadata
│ │ ├── CommitHash
│ │ ├── CommitSeparator
│ │ └── CommitTimestamp
│ └── CommitActions
│ └── CommitCopyButton
└── CommitContent
└── CommitFiles
└── CommitFile
├── CommitFileInfo
│ ├── CommitFileStatus
│ ├── CommitFileIcon
│ └── CommitFilePath
└── CommitFileChanges
├── CommitFileAdditions
└── CommitFileDeletionsCommitHeader puts an invisible button over the whole row: a click anywhere on it opens the file list, and CommitActions sits above that button, so the copy button still takes its own click.
Usage
import {
Commit, CommitActions, CommitContent, CommitCopyButton, CommitFile,
CommitFileAdditions, CommitFileChanges, CommitFileDeletions,
CommitFileIcon, CommitFileInfo, CommitFilePath, CommitFiles,
CommitFileStatus, CommitHash, CommitHeader, CommitInfo, CommitMessage,
CommitMetadata, CommitSeparator, CommitTimestamp,
} from "@/components/ui/commit";<Commit>
<CommitHeader>
<CommitInfo>
<CommitMessage>Add user authentication flow</CommitMessage>
<CommitMetadata>
<CommitHash>a1b2c3d</CommitHash>
<CommitSeparator />
<CommitTimestamp date={new Date("2026-10-21T14:30:00Z")} />
</CommitMetadata>
</CommitInfo>
<CommitActions>
<CommitCopyButton hash="a1b2c3d4e5f6" />
</CommitActions>
</CommitHeader>
<CommitContent>
<CommitFiles>
<CommitFile>
<CommitFileInfo>
<CommitFileStatus status="added" />
<CommitFileIcon />
<CommitFilePath>src/auth/login.tsx</CommitFilePath>
</CommitFileInfo>
<CommitFileChanges>
<CommitFileAdditions count={45} />
<CommitFileDeletions count={0} />
</CommitFileChanges>
</CommitFile>
</CommitFiles>
</CommitContent>
</Commit>Demos
File statuses
The four values of status on CommitFileStatus, one file each: added in green, modified in amber, deleted in red and renamed in blue, each with its letter and the word for screen readers. A count of 0 renders nothing, so the renamed file shows no line counts. The colors come from the theme's status tokens, so they follow light and dark like the Badge does.
Author
CommitAuthor with a CommitAuthorAvatar at the start of the header: one with a picture in src, one with only its initials. Put the name in CommitMetadata beside the hash. Show the author when people and agents commit to the same branch; when the agent made every commit, the avatar is noise.
History
Three commits from one task, newest first, each closed until you open it. The metadata counts the files, so the reader knows how much is inside before opening it. Use a column of cards for a short run of commits; a long log needs a list of its own.
Copy
CommitCopyButton copies the full hash in hash while the header shows seven characters. onCopy runs once it's on the clipboard, onError when the browser refuses, and timeout sets how long the check stays, 1.5 seconds here. The button also announces Copied to screen readers.
AI SDK
Give the agent a tool that commits and returns the commit, gitCommit in this example: its hash, message, date and changed files, from git show --numstat. Render a Commit for each call whose output has arrived.
const commits = message.parts
.filter((part) => part.type === "tool-gitCommit")
.filter((part) => part.state === "output-available")
.map((part) => part.output);Each output maps onto the parts:
| Output field | Part |
|---|---|
message | CommitMessage |
hash | CommitHash (its first 7 characters) and CommitCopyButton's hash |
date (an ISO string) | CommitTimestamp's date, as new Date(date) |
files[].status | CommitFileStatus's status: added, modified, deleted or renamed |
files[].additions, files[].deletions | CommitFileAdditions and CommitFileDeletions' count |
Migrating from AI SDK Elements
If you added Commit from AI SDK Elementscomponents/ai-elements/commit.tsx. Install ours with the command above and import from @/components/ui/commit instead: every part keeps its name and props, so the code that uses it keeps working. What changes:
CommitHeaderis a row with a trigger button laid over it, so the copy button is no longer a button inside a button.labelnames that trigger for screen readers (Changed files by default), and a chevron at the end shows whether the list is open.CommitActionsno longer stops the click: it sits above the trigger instead.CommitTimestamppicks its unit, from seconds to years, where AI SDK Elements always counted days. It writes the date itself until the page runs, so the server and the browser agree, andlocalesets its language.CommitAuthorAvataralso takessrcandaltfor a picture.CommitFilesis aulandCommitFileanli.
FAQ
How do I install the Commit component in React?
Run the command in the Installation section above: it adds commit to your components/ui folder with the Avatar, Button and Collapsible it uses.
The command uses the shadcn CLI.
What file statuses does Commit show?
Four: added, modified, deleted and renamed, set with status on CommitFileStatus. Each shows its letter (A, M, D, R) in its own color, and says the whole word to screen readers. The File statuses demo has one of each.
How do I show the lines added and removed?
Put CommitFileAdditions and CommitFileDeletions in CommitFileChanges and pass each its count. They show +45 in green and −3 in red, and a count of 0 renders nothing, so a renamed file with no edits stays clean.
How do I show the changed files open at first?
Set defaultOpen on Commit. It's closed by default; open and onOpenChange control it from your own state.
How does the copy button on a Commit work?
CommitCopyButton writes its hash to the clipboard and shows a check for timeout milliseconds, 2000 by default.
onCopy runs once it's copied, and onError gets the error when the browser refuses.
API Reference
Commit
data-slot="commit"
open?boolean
Whether it's open. Pair with onOpenChange to control it.
defaultOpen?boolean
Whether it starts open, when you don't control open.
onOpenChange?{ bivarianceHack(open: boolean): void; }["bivarianceHack"]
Called when it opens or closes.
- Type
{ bivarianceHack(open: boolean): void; }["bivarianceHack"]
disabled?boolean
Whether it's disabled.
asChild?boolean
Merge props onto the child element instead of rendering a host.
className?string
Merged with the part's classes.
CommitActions
<div> data-slot="commit-actions"
className?string
Merged with the part's classes.
CommitAuthor
<div> data-slot="commit-author"
className?string
Merged with the part's classes.
CommitAuthorAvatar
data-slot="commit-author-avatar"
initialsstring
The letters shown until the picture loads, or without one.
alt?string
The picture's text alternative: empty when the author's name is beside it.
- Default
""
size?"default" | "sm" | "lg"
The size.
- Type
"default" | "sm" | "lg"
src?string
The author's picture.
asChild?boolean
Merge props onto the child element instead of rendering a host.
className?string
Merged with the part's classes.
CommitContent
data-slot="commit-content"
disableAnimation?boolean
Opens and closes it at once, without the height animation.
forceMount?true
Used to force mounting when more control is needed. Useful when controlling animation with React animation libraries.
asChild?boolean
Merge props onto the child element instead of rendering a host.
className?string
Merged with the part's classes.
CommitCopyButton
hashstring
The full hash it copies.
clickEffect?boolean
Apply a click effect to the button.
- Default
true
isLoading?boolean
Show a loading indicator.
- Default
false
onCopy?() → void
Called once the hash is on the clipboard.
- Returns
void
onError?(error: Error) → void
Called when the browser refuses the clipboard.
- Parameters
error– Error- Returns
void
pill?boolean
Fully rounded corners.
- Default
false
size?"default" | "icon" | "icon-lg" | "icon-md" | "icon-sm" | "icon-xl" | "icon-xs" | "lg" | "md" | "sm" | "xl" | "xs"
Ark default: md.
- Type
"default" | "icon" | "icon-lg" | "icon-md" | "icon-sm" | "icon-xl" | "icon-xs" | "lg" | "md" | "sm" | "xl" | "xs"- Default
"icon-sm"
timeout?number
How long the check shows after a copy, in milliseconds. * * @default 2000.
- Default
2000
variant?"default" | "destructive" | "ghost" | "link" | "outline" | "secondary"
Ark default: default.
- Type
"default" | "destructive" | "ghost" | "link" | "outline" | "secondary"- Default
"ghost"
asChild?boolean
Merge props onto the child element instead of rendering a host.
className?string
Merged with the part's classes.
CommitFile
<li> data-slot="commit-file"
className?string
Merged with the part's classes.
CommitFileAdditions
<span> data-slot="commit-file-additions"
countnumber
Lines added. Nothing renders at 0.
className?string
Merged with the part's classes.
CommitFileChanges
<div> data-slot="commit-file-changes"
className?string
Merged with the part's classes.
CommitFileDeletions
<span> data-slot="commit-file-deletions"
countnumber
Lines removed. Nothing renders at 0.
className?string
Merged with the part's classes.
CommitFileIcon
data-slot="commit-file-icon"
className?string
Merged with the part's classes.
CommitFileInfo
<div> data-slot="commit-file-info"
className?string
Merged with the part's classes.
CommitFilePath
<span> data-slot="commit-file-path"
className?string
Merged with the part's classes.
CommitFileStatus
<span> data-slot="commit-file-status"
statusCommitFileStatusValue
What the commit did to the file: its letter and color.
className?string
Merged with the part's classes.
data-status?string
Mirrors status.
CommitFiles
<ul> data-slot="commit-files"
className?string
Merged with the part's classes.
CommitHash
<span> data-slot="commit-hash"
className?string
Merged with the part's classes.
CommitHeader
<div> data-slot="commit-header"
label?string
What the button that opens the file list is called by assistive tech.
- Default
"Changed files"
className?string
Merged with the part's classes.
CommitInfo
<div> data-slot="commit-info"
className?string
Merged with the part's classes.
CommitMessage
<span> data-slot="commit-message"
className?string
Merged with the part's classes.
CommitMetadata
<div> data-slot="commit-metadata"
className?string
Merged with the part's classes.
CommitSeparator
<span> data-slot="commit-separator"
className?string
Merged with the part's classes.
CommitTimestamp
<time>
dateDate
When the commit was made.
locale?string
The locale the words are written in. Fixed by default, so the server * and the browser write the date the same way. * * @default "en-US".
- Default
"en-US"
className?string
Merged with the part's classes.











