Skip to content

shadcn.io is an independent project built on shadcn/ui

Components

Free

Commit for Radix UI

A commit an agent made, with its message, hash, author and the files it changed. For React with Radix UI, when a coding agent reports its work.

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.

Preview width

Installation

Sign in to get your install command
Free with an account. It carries your token, so the CLI installs everything in one go.

Anatomy

Commit anatomy: root, header, message, copy button, content, file status
Commit
├── CommitHeader
│   ├── CommitAuthor
│   │   └── CommitAuthorAvatar
│   ├── CommitInfo
│   │   ├── CommitMessage
│   │   └── CommitMetadata
│   │       ├── CommitHash
│   │       ├── CommitSeparator
│   │       └── CommitTimestamp
│   └── CommitActions
│       └── CommitCopyButton
└── CommitContent
    └── CommitFiles
        └── CommitFile
            ├── CommitFileInfo
            │   ├── CommitFileStatus
            │   ├── CommitFileIcon
            │   └── CommitFilePath
            └── CommitFileChanges
                ├── CommitFileAdditions
                └── CommitFileDeletions

CommitHeader 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.

Preview width

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.

Preview width

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.

Preview width

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.

Preview width

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 fieldPart
messageCommitMessage
hashCommitHash (its first 7 characters) and CommitCopyButton's hash
date (an ISO string)CommitTimestamp's date, as new Date(date)
files[].statusCommitFileStatus's status: added, modified, deleted or renamed
files[].additions, files[].deletionsCommitFileAdditions and CommitFileDeletions' count

Migrating from AI SDK Elements

If you added Commit from AI SDK Elements (opens in a new tab), your project has a components/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:

  • CommitHeader is a row with a trigger button laid over it, so the copy button is no longer a button inside a button. label names that trigger for screen readers (Changed files by default), and a chevron at the end shows whether the list is open.
  • CommitActions no longer stops the click: it sits above the trigger instead.
  • CommitTimestamp picks 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, and locale sets its language.
  • CommitAuthorAvatar also takes src and alt for a picture.
  • CommitFiles is a ul and CommitFile an li.

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.

Why does the Commit timestamp show a date first?

The server can't know the reader's time, so CommitTimestamp writes the date in UTC, then switches to words such as 2 hours ago or yesterday once the page runs. Hovering shows the full date and time. Pass children to write your own words.

Can I open a Commit with the keyboard?

Yes. The header's trigger is a real button: Tab reaches it, and Enter or Space opens and closes the file list. Tab then moves on to the copy button, which sits above the trigger, not inside it.

API Reference

Commit

data-slot="commit"

PropType
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"

PropType
className?string

Merged with the part's classes.

CommitAuthor

<div> data-slot="commit-author"

PropType
className?string

Merged with the part's classes.

CommitAuthorAvatar

data-slot="commit-author-avatar"

PropType
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"

PropType
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

PropType
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"

PropType
className?string

Merged with the part's classes.

CommitFileAdditions

<span> data-slot="commit-file-additions"

PropType
countnumber

Lines added. Nothing renders at 0.

className?string

Merged with the part's classes.

CommitFileChanges

<div> data-slot="commit-file-changes"

PropType
className?string

Merged with the part's classes.

CommitFileDeletions

<span> data-slot="commit-file-deletions"

PropType
countnumber

Lines removed. Nothing renders at 0.

className?string

Merged with the part's classes.

CommitFileIcon

data-slot="commit-file-icon"

PropType
className?string

Merged with the part's classes.

CommitFileInfo

<div> data-slot="commit-file-info"

PropType
className?string

Merged with the part's classes.

CommitFilePath

<span> data-slot="commit-file-path"

PropType
className?string

Merged with the part's classes.

CommitFileStatus

<span> data-slot="commit-file-status"

PropType
statusCommitFileStatusValue

What the commit did to the file: its letter and color.

className?string

Merged with the part's classes.

AttributeType
data-status?string

Mirrors status.

CommitFiles

<ul> data-slot="commit-files"

PropType
className?string

Merged with the part's classes.

CommitHash

<span> data-slot="commit-hash"

PropType
className?string

Merged with the part's classes.

CommitHeader

<div> data-slot="commit-header"

PropType
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"

PropType
className?string

Merged with the part's classes.

CommitMessage

<span> data-slot="commit-message"

PropType
className?string

Merged with the part's classes.

CommitMetadata

<div> data-slot="commit-metadata"

PropType
className?string

Merged with the part's classes.

CommitSeparator

<span> data-slot="commit-separator"

PropType
className?string

Merged with the part's classes.

CommitTimestamp

<time>

PropType
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.