shadcn.io is not affiliated with official shadcn/ui
Compare Two Documents Command Menu Block for Ark UI
A document tool's command menu shown open over two document columns: seven versions to choose from, exactly two kept (a third replaces the oldest), and a Compare row that draws the added and removed clauses in a band.
Installation
Overview
Choose exactly two versions and see what changed with this compare command menu for React with Ark UI. It opens from the Documents page in Twinleaf, a document tool, whose header holds an outline field with its ⌘ K cap, and two document columns are drawn under a soft scrim inside a hairline frame with a plus mark on each corner. The menu is the catalog Command in the wide size: seven documents in three families (a services agreement in four versions, a privacy addendum in two and an order form), each row with its version Badge, its size and which pick it is. You keep two at a time and a third pick replaces the oldest, which the row says ("First pick · replaced next") and the band under the list repeats. With two chosen, a first row "Compare … with …" appears; Enter on it fills the band with the changes clause by clause, each line a + or − sign, the clause and the word Added or Removed, with a count such as "2 added, 2 removed". For preview the menu is drawn open in place when the page loads; the field, or Ctrl or ⌘ K while focus is in the block, opens the real command dialog with the same documents, picks and query. For contracts, specs, config revisions and any list where the useful action needs a pair.
FAQ
Why is the menu already open, and what do I keep?
So you can see it without a click. On load the menu is the Command drawn inline over a picture of two documents, in a plain shell that is not modal, so nothing is trapped, hidden or focused and the page around the preview keeps working. The header's field opens the real command dialog, modal, with its focus trap, Escape and focus return, and the inline copy stays closed until a reload. Both show the same Palette and share the block's state, so the picks or a comparison in the copy is in the dialog. In your app keep the dialog and drop the copy: the "in-place" state, the scrim with its shell and the Escape and blur effects.
Why exactly two, and what does a third pick do?
A comparison needs a pair, so the block never holds more or fewer than two. The oldest pick is the one that goes, which keeps the document you just chose and the one you chose before it, and the status line names the one that was dropped. Choosing a picked document again unpicks it, and any change to the picks puts the band back to its hint until you press Compare again.
How is the diff worked out?
Every document is a short list of clauses with a key shared by its versions, and diffOf walks the keys in a fixed order: the same text is unchanged, different text is a Removed line then an Added line, and a clause only one side has is one or the other. It is a plain function, so the same pair always gives the same lines, and across families (no shared keys) everything reads as removed and added. For long text use a real diff library on lines or words in the same shape.
Is the changes band accessible?
The band is a scroll region you can reach with Tab, named "Changes between the two documents", and it keeps one height whether it holds the hint or twenty lines. The + and − signs are decoration; each line also carries the word Added, Removed or Unchanged, and removed text is struck through, so the meaning never rests on the sign or the strike alone. The status line reads the summary when you compare.
What stays local, and how do I wire it?
All of it. The seven versions, their sizes and their clauses are typed constants and nothing is uploaded. In your app fill DOCS from your document store, with clauses coming from your own paragraph or section model, and keep the two chosen ids in the URL if you want a comparison to be a link.
Is it accessible from the keyboard?
Yes. Type to search, the arrow keys move through the rows, Enter picks or unpicks a document, Enter on the first row compares, and Tab reaches the changes band to scroll it. Escape closes the menu with focus on the field, and Ctrl or ⌘ K opens the dialog while focus is inside the block, and only then. The rows are options of a combobox and the first is highlighted when it opens.