Skip to main content
These rules target the places where UIs — especially generated ones — consistently fail with real content and real users.

Respect line length

Body text sits between 45–75 characters per line; the sweet spot is 60–70. Under 40, the eye develops a jittery rhythm; over 80, it loses its place on the return sweep. This is a documented perceptual constraint, not an aesthetic preference. Watch for the classic failures: full-width card descriptions, hero subtitles spanning the viewport, helper text stretching under a wide form. Give prose its own max-width, independent of its container. Longer lines also need more generous line height — see Typography for the pairing table.

Never sacrifice accessibility for hierarchy

De-emphasis (lighter, muted text) taken too far produces text real humans can’t read. Your “tertiary” color is the lightest color that still passes 4.5:1 at body sizes. When in doubt, err toward slightly too much contrast: a secondary color that’s a touch dark still reads as secondary through size and weight; a color that fails contrast is actively harmful. Rules of thumb:
  • Never use color as the only differentiator — vary size or weight too.
  • Test the extremes: lightest text on lightest background is the most dangerous pair. In Sundial terms: verify contrastWeak on surfaceBg in both brightness modes before using it for anything that must be read.
  • Dark mode reverses the math but not the ratios — light-on-dark still needs 4.5:1.
  • Placeholder text usually fails by default; ensure contrast or don’t rely on it for essential information.

Design for content overflow and edge cases

Sample data is always perfectly sized; real data never is.
  • Truncate supplementary content, wrap primary content. Single-line ellipsis for names in constrained spaces; 2–3-line clamping for previews; never truncate an error message. (Sundial components use AutoSizeText with maxLines + ellipsis — see StyledListTile.)
  • Empty states are mandatory. Every list, table, or feed will eventually be empty. Each empty state needs: what would be here, why it’s empty, and an action to resolve it.
  • Stress-test the extremes before calling a layout done:
When writing sample data, include at least one stress-test data point — it forces edge-case handling during the build, not after.

Maintain alignment consistency

Center-aligning everything produces a wedding invitation: decorative, impossible to scan. The eye scans by returning to a consistent starting edge — left-aligned text creates that edge. Pick an edge and stick to it within any section. And the key distinction: center the container, left-align the content within it.