Skip to main content

Start with too much white space

Most developers add white space reactively — something looks cramped, so they add margin until it stops looking bad. The result is the minimum breathing room: functional, never great. Do the opposite: start with way too much space, then remove until you’re happy. What feels like “a little too much” focused on a single element ends up “just enough” in a complete UI. Cramped interfaces feel stressful — the opposite of what Ash should communicate. Dense UIs (dashboards, data tables) are legitimate — but density should be a deliberate choice, never the default.

Follow a spacing scale exactly

Agonizing over 120px vs 125px is slow and produces inconsistency. Use a constrained scale where no two adjacent values are closer than ~25% apart — at small sizes a 4px jump is significant; at large sizes it’s imperceptible. The reference scale (4px base): 4, 8, 12, 16, 24, 32, 48, 64, 96, 128. Need space? Grab a value from the scale. Not enough? Jump to the next value — don’t nudge by 2px. The constraint is the point. Never use arbitrary values; if a value feels “close enough,” use the nearest scale value instead.
Sundial has no exported spacing-token class — the scale is a convention. Common values in the codebase are 4, 8, 12, 16, 20; see Shape & Spacing for what components actually use, and prefer Flutter’s Column(spacing: …) / Row(spacing: …) over SizedBox separators.

Avoid ambiguous spacing

One of the most damaging spacing mistakes. When spacing alone defines grouping, equal spacing everywhere destroys relationships — a form label equidistant between two inputs belongs to neither. The rule: space within a group < space between groups. Always. Without exception.
  • Form labels sit tight to their inputs; field groups sit apart
  • More space above a heading than below it — it belongs to the section it introduces
  • Gap between icon and its label < gap between one icon-label pair and the next
  • List item spacing > line height within an item
If two elements are closer to each other than to their surroundings, they are implicitly grouped — make sure that grouping is intentional.

You don’t have to fill the screen

If content needs 600px, give it 600px — extra space around the edges is visual relief, and stretched content hurts readability. Give content a comfortable max-width on large screens. If something feels too narrow, don’t stretch it — think in columns and put supporting context beside it. Design mobile-first (~400px), then expand — you’ll change less than you expect.

Grids are a tool, not a religion

12-column grids outsource decisions that deserve judgment, and percentage widths make everything fluid when not everything should be:
  • Sidebars should be fixed-width — 25% is too wide on a big screen and too narrow on a small one.
  • Use max-width, not column counts, for centered content — a card that looks best at 500px should be 500px everywhere.
  • A consistent spacing system produces better results than forcing content into rigid columns.

Relative sizing doesn’t scale

Don’t make everything proportional to a single base (“heading is 2.5× body”). Large elements on large screens must shrink faster than small elements as the screen shrinks — the ratio between largest and smallest text should be less extreme on mobile. The same goes for component internals: large buttons get disproportionately generous padding, small buttons disproportionately tight. Components at different sizes need independent design decisions.

The human test

Every spacing decision should look like a human designer made it. If a layout looks “off” but you can’t pinpoint why, check for inconsistent margins, misaligned elements, or uneven padding — it’s almost always one of those.