UI/UX
The principles every screen follows, the spacing and layout it sits on, and live examples of the @workspace/ui components. Toggle the theme in the header to check both modes.
Experience
People running a business use the product all day. It has to respond at once, never lose their work and behave the same way every time.
Principles
What every screen should do, whatever it shows.
Patterns
Moments that come up again and again, handled the same way everywhere.
| Moment | Do this | Why |
|---|---|---|
| Loading a view | A skeleton shaped like the content | The layout doesn't jump when data lands. |
| Saving a change | Apply it at once. If the server refuses, roll it back and show a toast | Nobody waits on the network after every edit. |
| Editing long text | Autosave with a quiet saving/saved status | No save button to forget. |
| Deleting | Confirm with the item's name and "This can't be undone." | A deliberate pause only where a mistake is permanent. |
| An empty list | Say what will be here and offer the first step | Someone looking at an empty list needs to know how to start. |
| A form error | Inline, under the field, once it's been left | The fix is next to the problem. |
Accessibility
WCAG 2.2 AA, checked in both themes. It's the minimum, not a feature.
- Keep body text at 4.5:1 contrast and UI boundaries at 3:1.
- Label every control, and give icon-only buttons an aria-label.
- Keep focus visible, and return it where it was when a dialog closes.
- Honour reduced motion, and make targets at least 24px.
- Use colour alone to carry meaning.
- Hide essential information in tooltips or on hover.
- Trap focus outside dialogs, or remove outlines without a replacement.
Foundations
Tailwind's scale, kept small: five gaps, one radius family, five breakpoints.
Spacing
Reach for gap-4 first. Space with gap on the parent, not margins on children.
gap-1.50.375remLabel to input, icon to textgap-30.75remTight groups: toolbar buttons, chipsgap-41remThe default: grids, cards, form fieldsgap-82remRelated blocks within a sectiongap-164remBetween the sections of a page
- Use the Tailwind scale, and these five steps before any other.
- Design at 375px first. Nothing may scroll sideways on a phone.
- Arbitrary values like p-[13px] to nudge something into place.
- Nest max-width containers, or pad a card's children instead of the card.
Radii
Every radius is a multiple of --radius (0.45rem). Buttons and badges use rounded-2xl. Cards and dialogs go up to 24px.
rounded-sm4.3pxrounded-md5.8pxrounded-lg7.2pxrounded-xl10.1pxrounded-2xl13.0pxrounded-3xl15.8pxrounded-4xl18.7pxBreakpoints
Tailwind's defaults, mobile first: unprefixed classes are the phone layout.
| Prefix | From | What changes |
|---|---|---|
| None | < 640px | One column. Actions go full width. |
| sm | 640px | Two-column grids. |
| md | 768px | Page padding grows, and the app sidebar stops being a sheet (useIsMobile). |
| lg | 1024px | Three columns. Secondary panels, like this table of contents, appear. |
| xl | 1280px | Content stops growing at max-w-screen-xl. |
Page structure
The classes these guideline pages use.
| Role | Classes |
|---|---|
| Page width | mx-auto w-full max-w-screen-xl |
| Reading width | max-w-2xl (prose, descriptions) |
| Page padding | px-4 py-8 md:px-8 md:py-12 |
| Sections | flex flex-col gap-16 |
| Card grids | grid gap-4 sm:grid-cols-2 lg:grid-cols-3 |
Actions
Everything a person presses. One primary action per view.
Button
Default (orange) for the one primary action. Outline or secondary for the rest, ghost in toolbars, and destructive only for what can't be undone.
Button sizes
Default (h-8) almost everywhere. Use sm and xs in dense rows, and lg only for a lone call to action.
Badge
Short status and counts. Secondary or outline by default, so the orange stays for what needs attention.
Button group
Related actions joined into one control.
Toggle group and segmented control
Toggle groups for formatting and multi-select. To switch between views, use the segmented control and nothing else.
Forms
React Hook Form and Zod do the work underneath. These are the controls on top.
Field and input
Every input sits in a Field with a label. Errors appear under their own field, never in a list at the bottom of the form.
As it should appear on proposals.
Input group
An input with an icon, prefix or unit attached.
Select and textarea
Select for one of a known list. Textarea for anything longer than a line.
Checkbox, radio, switch and slider
Checkboxes for independent options, radios for one of a few, switches for settings that apply at once.
Layout
The containers that hold content.
Card
Frosted glass with the orange top rule. Title in serif, description muted, actions in the footer.
+12%vs last month
Tabs
Different views of the same thing. Keep labels to one or two words. Default (pill) tabs switch views inside a card or panel. Line tabs head a whole page or dialog, as in settings.
Accordion
Secondary detail a reader may not need. Never hide what they must read.
Item
A row in a list: media, title, description and actions.
4 members, 1 pending invitation
Marketing
What the marketing site's sections are built from.
Section header
The words that open a section: eyebrow, heading, lead, then one or two actions. Every part is optional. The heading's size and its level in the page outline are set apart.
Planning
Plan the week in minutes
See every project's next step in one place, and move it with a drag.
Centred, and a size smaller
Drawn at heading 3, still an h2 in the outline.
Bento grid
Cards in mixed sizes. One column on a phone, two from 640px, three from 1024px. Small cards fill the gaps, so keep each card independent of its neighbours.
Media frame
The box every image, video and embed sits in. A fixed shape crops the media to cover it; original keeps the media's own shape.
Section backdrop
Brand artwork behind a section a page is built around (the hero, the pricing plans, the closing call to action): the glow, the dot field from Brain Space, or the dot-matrix Earth or Moon from Mission Control. Never on adjacent sections, and never two in view at once.
Glow
Dot field
Earth
Moon
Feedback
How the app tells people what's happening.
Alert
Inline, persistent messages about the thing in front of the reader. Always an icon, a title and what to do.
Toast
A short-lived confirmation of something that happened off-screen, or a failure. Name the thing and keep it to one sentence.
Skeleton and spinner
Skeletons, shaped like what's coming, for views and sections. A spinner only inside a button or inline, for an action in progress.
Empty
An empty list says what will be here and offers the first step.
Tooltip
Names an icon-only control. Never the only place information lives.