shadcn.io is not affiliated with official shadcn/ui
Font Picker Dialog Block for React
A writing app's document page with its type style dialog shown open: a family from three system stacks, weight, size from 12 to 48 pixels, line height and letter spacing, a live specimen and the CSS it makes with a Copy button.
Installation
Overview
Let writers set the type of a page and see it as they go, with this type style dialog for React with Base UI. It opens from a document in Glyphlane, a writing app: the header holds an outline Button, and the document is drawn under a soft scrim inside a hairline frame with a plus mark on each corner. The dialog picks among three system families, Sans, Serif and Mono, each shown as an "Aa" in its own face in a Radio Group, then a weight and a line height with Toggle Groups, a size from 12 to 48 pixels with a Slider, and a letter spacing with a Select. Beside the controls a specimen restyles as you change them, with the CSS they make and a Copy Button. Apply to document, the only Shine Button, restyles the title and text of the page behind it. For preview the dialog is drawn open in place when the page loads; the header button opens the real Dialog, with the same state. For editors, note apps, reading modes and any app that lets people choose their type.
FAQ
Why is the dialog already open, and what do I keep?
So you can see it without a click. On load the dialog is a copy drawn in place over the page: a native dialog element that isn't modal, so nothing is trapped, hidden or focused, and the page around the preview keeps working. The header's Type style button opens the real Dialog, modal, with its focus trap, Escape and focus return, and the copy stays closed until a reload. Both show the same TypeFields component and share the block's state, so what you set in the copy is there in the real one. In your app keep the Dialog and drop the copy: the "in-place" state, the scrim and the dialog element inside the frame.
Why only three families, and are any fonts loaded?
No font is loaded or downloaded. Each family is a stack of system fonts that already exist on the device: ui-sans-serif and system-ui, ui-serif and Georgia, ui-monospace and a monospace fallback. That keeps the dialog instant, private and accurate, because what you see is what the device will draw. The dialog says "Uses your system fonts" for the same reason. To offer web fonts, add entries to FAMILIES with their font-family stacks, load them with your own @font-face or font service, and wait for them before applying.
What is the CSS line, and what does Copy put on the clipboard?
The specimen's style written as a font shorthand (weight, size over line height, family stack) and a letter-spacing line, for example font: 500 18px/1.5 ui-serif, Georgia, serif;. Copy puts both lines on the clipboard, which is the only thing the page touches, and says "Copied" to screen readers. If the browser refuses, for instance on a page not served over HTTPS, the button says it couldn't copy.
What stays local, and how do I wire it for real?
Everything. Apply to document restyles the drawn page in local state and says so in a polite status message; nothing is stored. In your app save the five choices (family id, weight, size, line height, letter spacing) with the document or the user's preferences in apply, and map them to the CSS variables or classes your editor uses. Reset to the saved values when the dialog closes, as Cancel does here.
Is it accessible from the keyboard?
Yes. The real dialog is named by its title and described by its sentence, focus is trapped while it is open, and Escape, Cancel and the close button return focus to the header button. The trigger is passed to DialogTrigger through render, and the dialog is controlled with open and onOpenChange. The copy shown on load moves no focus; Escape inside it and its close button close it and put focus back on the header button. The families are a radio group moved with the arrow keys, the weight and line height are toggle groups, and the size slider moves with the arrow keys, Home and End and says its value in pixels. The specimen is decoration and hidden from assistive technology; the CSS line states the values in text.
How does it look on a phone?
The specimen moves above the controls, so you see the effect of each change as you scroll the controls beneath it. The copy shown on load docks to the foot of the page as a bottom sheet with Apply to document pinned at the bottom. The real dialog keeps the Dialog's own phone layout: a sheet stuck to the bottom of the screen.
Related
- Pro
A brand-kit page with its colour dialog shown open: an inline saturation and hue picker with opacity, HEX, RGB and HSL fields, eight named presets, five recent colours, a Copy button and a contrast readout against white and dark text.
- Pro
Appearance Settings
Appearance and localeAn appearance settings panel that previews instead of applying: a drawn app window that wears the choices, theme and contrast cards with a drawn thumbnail each, a text-size slider with a sample sentence and a reduce motion switch with a replay.
- Pro
A time tracker's Today page with a preferences sheet shown open where each setting shows its effect: a theme choice over a preview card, a text size and a reduce-motion switch acting on a sample, a default view and two behaviour switches.
- Pro
Table Insert Dialog
Drawers and popoversA team wiki's table picker shown open under its toolbar: an eight by eight grid of buttons that grows with hover and the arrow keys, the size said in words, a header-row switch, and a drawn table landing at the cursor.
- 12Pro
Sort Options Dialog
Notes and editingA data-grid tool's sort dialog shown open: up to three rules with a field and a direction each, Move up, Move down and Remove, a sorted five-row preview with the sorted columns numbered, and the table re-sorting on apply.
- Pro
Brand Colour Picker Form
Numbers and pickersA brand colour field that makes a scale: a hex input and the colour picker kept in sync, eight named presets, and five derived steps by lightness, each with its hex and a copy button.