Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Code Diff Skeleton Block for React

A pull request's changed file that loads in place: the line-number gutter stays while bars become the path, the +4 -3 count and fifteen lines of code with plus and minus signs.

Framework
UI library

Preview

Preview width

Installation

Part of Pro
Pro unlocks the code and one-line install of every Pro button and text effect, plus the MCP for your AI editor.
Have Pro already? Sign in to open it.Opens here as soon as you're Pro.

Overview

Show a diff while it loads, then swap the code in without moving anything, with this code diff skeleton for React with Base UI. A hairline frame with a plus mark on each corner holds a band for the changed file and a unified diff as a native table, from Rampion, a code-review tool. The gutter of old and new line numbers is drawn from the first paint; the file's path, its change count, the hunk header and the fifteen lines of TypeScript are Skeleton bars that become the data in the same cell, line by line, when you press Load. An added line is told apart by a plus and a heavier tint, a removed one by a minus, a lighter tint and muted text, so no line depends on a color, and screen readers hear "Added" or "Removed". The code pans sideways in a named region with the gutter pinned to the start. It's built from Skeleton, Button and Guides, with a CSS entrance only. For pull requests, commit views and any code that waits for a query.

FAQ

What stays local, and how do I wire it to a real query?

Nothing is fetched. The fifteen lines are typed in RAW as compact diff lines (a space, a minus or a plus, then the code), and the numbers, the counts and the hunk header are worked out from them. Load starts a 700 millisecond timer, and when it ends the phase becomes ready and the data swaps in; Reload goes back to the bars and in again. To wire it for real, delete the timer, the Load button and the polite line, and set data-state (loading or ready) and aria-busy on the region from your query's pending state, or use the bars as a Suspense fallback and render the real data when it arrives. The bars are derived from the same data as the real thing, so keep one component for both.

Why aren't added and removed lines green and red?

Hue is not a reliable signal, so a changed line is marked by its sign, by a tint mixed from the foreground and card tokens (8 percent for added, 3 percent for removed, with muted text) and, for screen readers, by a hidden "Added" or "Removed". The tint only appears once the data is in, so the bars are not striped. It follows the theme in light and dark, and the code itself is colored by the same theme tokens as the catalog's syntax text.

Does the diff keep its height while it loads?

Each bar and its line of code sit in one grid cell, so the larger of the two sets the cell's box and the swap changes nothing around it. Every row is a fixed 24 pixels, the gutter and the frame are real in both phases, and the polite line reserves two lines, so the panel is exactly as tall before, during and after loading at every width.

How does it look on a phone?

The table keeps its width and sits in a scrollable region named for the file, which a keyboard can focus and scroll. The two line-number columns and the sign column are pinned to the start with a solid background, so the numbers stay in view while the code pans under them. The table is always left to right, as code is, even in a right-to-left page.

Is it accessible?

The region is marked busy while it loads and carries a screen-reader-only "Loading the diff…", and the polite line announces what loaded once. The bars are hidden from assistive technology and the layer that isn't showing is invisible, so it is neither read nor focusable. The pulse stops when the data is in, and under reduced motion there is no pulse, no spinner and no stagger: the swap is instant. The table has a caption and hidden column heads, and the line numbers are hidden from assistive technology so only the code is read.