shadcn.io is not affiliated with official shadcn/ui
Focus Mode Dialog Block for Ark UI
A writing app's Drafts page with its focus settings shown open: a 25, 50 or 90 minute length, switches to hide the sidebar, mute notifications and show a word counter, a rest reminder, and a page that changes when the session starts.
Installation
Overview
Quiet a page for a while, with this focus mode dialog for React with Ark UI. It opens from the Drafts page of Stillroom, a writing space: the page's header holds an outline Focus Button, and the page, a sidebar of drafts, a toolbar with a bell and a text column, is drawn under a soft scrim inside a hairline frame with a plus mark on each corner. The Dialog has a Toggle Group for the length (25, 50 or 90 minutes), three Switches for what changes while you focus (hide the sidebar, mute notifications, show a word counter), and a Select for when to remind you to rest. The one Shine Button, Start focus session, closes the dialog and changes the page behind it: the drawn sidebar folds away, the bell shows as muted, the word counter appears, and the header's Focus becomes "Focus, 25 min" with an End session button that puts everything back. For preview the dialog is drawn open in place when the page loads.
FAQ
Why is the dialog already open?
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 Focus button in the header 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 FocusFields component and share the block's state, so a switch changed in place is changed 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.
What changes when a session starts?
Only this page. The sidebar column folds to nothing with a short transition (none under reduced motion) when the first switch is on, the bell is drawn muted when the second is on, a word count appears in the editor's corner when the third is on, and the header swaps Focus for a "Focus, 25 min" line and End session. End session reverses all of it and moves focus back to Focus. The length picks the minutes in that line.
Does it run a clock, mute anything or remind me?
No. There is no countdown here, so nothing ticks or ends by itself: End session is how a session stops. Mute notifications only changes the drawn bell, and the reminder choice is kept and echoed in the status line ("A reminder at the end") but nothing fires. For a real clock see the pomodoro timer dialog, which uses the catalog Timer.
What stays local, and how do I wire it for real?
Everything. The settings, the session and the word count are this page's state, and the status line says the demo only changes this page. In your app send the chosen settings to your own state when the form submits: hide the sidebar with your layout state, silence your own notification source (not the system's), start the timer your product needs, and schedule the reminder.
Where does focus go?
The real dialog is named by its title and described by its sentence, and focus starts on the length group. Starting a session closes it and moves focus to End session; ending it moves focus back to Focus. Escape and Cancel return focus to the Focus button. The trigger is wrapped in DialogTrigger with asChild, and the dialog is controlled with open and onOpenChange.
How does it look on a phone?
The copy shown on load docks to the foot of the frame as a bottom sheet with its actions pinned and the content scrolling above them. The drawn sidebar is already hidden on a phone, so that switch changes nothing you can see there; the bell and the word counter still do. The real dialog keeps the Dialog's own phone layout, a sheet from the bottom.