Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Page Preview Command Menu Block for React

A CMS's command menu shown open under the editor's Preview button: six pages, a Draft, Staging or Live switch, a drawn preview frame that resizes to Desktop, Tablet or Phone, and a Copy share link button.

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

Preview a page in any version and at any width with this CMS command menu for React with Base UI. It opens from the Preview button of an editor in Peekwell, a CMS with previews, whose header holds an outline field with its ⌘ K cap, and the editor is drawn under a soft scrim inside a hairline frame with a plus mark on each corner. The menu is the catalog Command hanging from the button at the end, beside a pane: six pages with a Draft, Staging and Live switch above the list, and the pane follows the highlighted page and shows a drawn frame of that version. A Device switch, Desktop, Tablet or Phone, resizes the frame in a width transition that reduced motion removes, and Copy share link copies a typed address. Enter opens the page in the editor's own preview frame behind the menu. On a phone the pane sits under the list and the device switch only changes the caption. For the 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 pages. For CMSs, page builders and any editor that previews before it publishes.

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 the editor, 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 a version or a device in the copy is still there 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.

What do Draft, Staging and Live change?

Each page carries its heading and its edit time in the three versions as typed data. The switch re-reads every row's second line and the pane's frame in the chosen version, so the same page shows different words in Draft and in Live. The switch always has one chosen, and the pane's caption states the version, the page and the time in words.

How does the device switch resize the frame?

The frame's width is a class chosen from the device: full, 72 percent or 38 percent of the pane, with a width transition that motion-reduce removes, so under reduced motion it jumps. Below the small breakpoint the pane is too narrow for the effect, so the frame stays full width and only the caption changes, naming the device and its width.

What does Copy share link copy?

A typed address built from the page and the version, for example https://peekwell.example/preview/pricing?version=staging, never the address of the page it sits on. It uses the catalog CopyButton; the status line says what was copied or that the browser refused.

What stays local, and how do I wire it?

All of it. The pages and versions are typed data and nothing is published. In your app render the real page in the frame (an iframe of your preview route, sized by the same width classes) and build the link from your preview token.

Is it accessible from the keyboard?

Type to filter, the arrow keys move through the rows and the pane follows, Enter opens the preview, and Escape closes the menu with focus back on the header's field; Ctrl or ⌘ K opens the dialog while focus is inside the block, and only then. The version and device switches and the Copy button sit outside the list so their keys stay their own. The rows are options of a cmdk listbox; the block turns off its own fuzzy filter and lists the rows itself.