shadcn.io is not affiliated with official shadcn/ui
Notification Preferences Dialog Block for React
A team chat inbox with a settings dialog shown open: a real table of notification kinds by channel with a switch in every cell, mixed-state column masters, reset and save, and a chip on the inbox that reports the saved count.
Installation
Overview
Let people choose how each kind of message reaches them, with this settings dialog for React with Base UI. It opens from the Inbox of Sparrowtalk, a team chat: the page's header holds an outline Notification settings Button, and the inbox itself, a toolbar with a gear and six message rows, is drawn under a soft scrim inside a hairline frame with a plus mark on each corner. The Dialog is a real table: five kinds down the side, Mentions, Replies, Deploys, Billing and Product news, each with a line of what it covers, and three channels across, Email, Push and SMS, with a Switch in every cell named for both, such as Mentions by email. Each column head holds a Checkbox, All email, that is mixed while only some of its column is on: pressing it turns the whole column on, then off. A line under the table counts what is on and what is not saved, Reset to defaults is a ghost button, and the only Shine Button saves. On a phone the columns shrink to icons with their names kept for assistive technology. Saving changes the inbox's chip to Preferences saved (6 on). For preview the dialog is drawn open in place when the page loads; the header button opens the real Dialog.
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 inbox: a native dialog element that isn't modal, so nothing is trapped, hidden or focused, and the page around the preview keeps working. The Notification settings 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 MatrixFields component and share the block's state, so what you changed 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.
How do the column boxes work?
Each one covers its own column. It is ticked when all five cells in the column are on, mixed when some are, and empty when none are. Pressing it when the column is all on turns the column off; pressing it in any other state turns the column on. The mixed state is drawn as a bar in solid foreground, on every library. Each box is named for its column, such as All email, so it reads clearly out of the table's context.
What does Save do, and what does closing do?
Save keeps the draft, closes the dialog and the inbox's chip reads Preferences saved with the number of cells on. Closing any other way, the close button, Escape or a click outside, drops what was not saved, so the dialog reopens as it was. A line under the table says how many cells are on and how many changes are not saved yet, and a polite message repeats it after each change. Reset to defaults puts the six default cells back in the draft; it saves nothing until you press Save.
How does the table fit on a phone?
It stays a table. Below a small screen the channel names hide and the three columns keep their icons, a mail, a bell and a message, with the names kept for assistive technology, and the descriptions wrap under the kinds. The boxes stay in the column heads at every width, and the body scrolls inside the dialog while the foot stays.
What stays local in the demo, and how do I wire it up?
All of it. The kinds, the channels, the defaults and what is saved are typed constants, and nothing is sent. In your app load the saved cells from the user's settings, post the draft from save, and keep a channel's cell off where the channel is not available to the person, for instance SMS with no verified number.
Is it accessible from the keyboard?
Yes. The real dialog is named Notification settings, focus starts inside and stays there until it closes, and Escape and the close button return focus to the header button. Every switch and every box is a tab stop named for its row and column, and Space flips it. 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 on the button.
Related
- Pro
Preference Matrix Notification
PreferencesA notification preference matrix: five kinds of notification down the page and four channels across, a checkbox in every cell, an all-types row that turns a channel on or off, marks on changed cells and an unsaved count.
- Pro
Notification Preferences Settings
NotificationsA notification settings panel: a channel strip with all-or-nothing checkboxes, a matrix of switches by activity and channel with a locked security email, quiet hours, and a save bar that counts unsaved changes.
- Pro
Email Preferences Settings
NotificationsA preference-centre page, the one an email footer links to: five topics each with a switch and a frequency menu, a digest mode, a computed email volume and an unsubscribe-from-everything that locks the rows and turns Save into Resubscribe.
- Pro
Notification Channels Settings
Alerts and auditA destinations window for alerts: a rail of Slack, email, PagerDuty, webhook and SMS destinations with a status word, beside the chosen one's routing by severity, a pause switch and a simulated test.
- Pro
Cookie Settings Dialog
Confirm and consentA newspaper's cookie preference centre shown open over its front page: four categories with switches and counts, Essential locked on, and for the chosen one a sentence and a table of its actual cookies, then Reject non-essential, Accept all and Save choices.
- Pro
Do Not Disturb Notification
Quiet and digestsA focus app's do-not-disturb panel: a status card that says in a sentence what the settings amount to, a 24-hour strip of the muted hours, one hour, until tomorrow or a nightly schedule, and the calls that still get through.