Skip to Content
StandardsUI & Design

UI & Design Standards

Aesthetics are everything. Visual design, polish, and attention to detail are critical. Every pixel matters, every interaction should feel intentional, and every screen should look like it was designed by someone who cares.

This philosophy guides every UI decision at Frequency. These standards ensure visual consistency, accessibility, and maintainability across all our applications.

The Component Hierarchy

When building UI, always follow this priority order:

1st

@frequencyads/components

Check the component catalog first. If Hero, AudioPlayer, CodeBlock, PrincipleCard, DosDonts, or any other shared component exists, use it. These components are already themed, accessible, and tested.

2nd

Mantine v8 Primitives

Paper, Card, SimpleGrid, Table, Group, Stack, Text, Title, Button, ActionIcon, Tabs, Accordion — Mantine v8 has 100+ components. Use them for everything else. Never raw HTML with Tailwind.

3rd

Custom Components

Only when neither the component library nor Mantine has what you need. Use CSS Modules for styling. Mark with a // TODO: Extract to @frequencyads/components comment if it could be reusable.

Styling Rules

What to Use

ApproachWhenExample
Mantine style propsOne-off spacing, colors, sizing<Text c="dimmed" mb="lg">
CSS ModulesComponent-specific stylesclasses.header
Theme tokensColors, spacing, typographyvar(--mantine-color-blue-6)

What to Avoid

ApproachWhy Not
Inline style objectsHard to maintain, no hover/responsive support
Tailwind classesInstalled but reserved for explicit human requests only
Hardcoded colorsBreaks theming and dark mode
CSS-in-JS runtimePerformance overhead, hydration issues

Color Rules

This is critical — hardcoded colors break dark mode and theming.

// ❌ NEVER hardcode colors <Box bg="white"> <Text color="#000000"> <Card style={{ backgroundColor: '#f5f5f5' }}> // ✅ ALWAYS use theme-aware values <Box bg="var(--mantine-color-body)"> <Text c="dimmed"> <Card bg="var(--mantine-color-default)"> // ✅ Use Mantine color tokens <Text c="blue.6"> <Badge color="green"> <ThemeIcon color="violet.4">

Available Brand Colors

TokenHexUsage
blue.6#169BDEPrimary actions, links
violet.6#7E57C2Secondary accents
red.6#E63459Errors, destructive actions
green.6#5AB267Success, confirmation
yellow.6#E79E26Warnings, attention
cyan.6#15C5DEInformation, highlights

See @frequencyads/brand for the full color palette and theme configuration.

Typography

Font Families

UseFontWeight Range
HeadingsMontserrat400–700
Body textSource Sans 3400–600
CodeJetBrains Mono / system mono400

Typography Scale

ElementSizeWeightLetter Spacing
Display60px700-2px
H148px700-2px
H236px700-1px
H324px600-0.5px
Body16px400normal
Small14px400normal
Label12px6000.3em (uppercase)

Loading Fonts

// In layout.tsx — fonts loaded via Google Fonts URL import { googleFontsUrl } from '@frequencyads/brand/typography'; // In <head> <link rel="stylesheet" href={googleFontsUrl} />

Theme Setup

Every app must wrap its content in a themed provider:

import { MantineProvider } from '@mantine/core'; import { frequencyTheme } from '@frequencyads/brand/mantine'; function App({ children }) { return ( <MantineProvider theme={frequencyTheme} defaultColorScheme="auto"> {children} </MantineProvider> ); }

Dark Mode

All Frequency apps should support dark mode by default:

  1. Never assume light mode — use theme-aware colors
  2. Test both themes — every component should look intentional in both modes
  3. Use defaultColorScheme="auto" — respects user’s system preference
  4. Dark backgrounds follow this palette: #000000 (body), #121212 (sections), #181818 (cards), #242424 (elevated surfaces)

Accessibility (WCAG 2.1 AA)

This is the floor, not the ceiling:

  1. Color contrast — minimum 4.5:1 for normal text, 3:1 for large text
  2. Focus indicators — every interactive element must have a visible focus state
  3. Keyboard navigation — all functionality accessible via keyboard
  4. Screen readers — meaningful alt text, ARIA labels where needed
  5. Reduced motion — respect prefers-reduced-motion for animations

Icons

// ✅ Use Tabler icons — lightweight outline SVGs import { IconSettings, IconUser } from '@tabler/icons-react'; <IconSettings size={20} stroke={1.5} /> // ❌ Never use emojis in UI (unless explicitly requested) // ❌ Never use filled/heavy icon styles

Interaction Patterns

Hover Effects

  • Subtle translateY(-4px) lift for cards
  • Border color lightens from rgba(255,255,255,0.05) to rgba(255,255,255,0.15)
  • Icon scales up slightly (scale(1.1))

Transitions

  • Default: 200ms ease for color changes
  • Cards: 300ms ease for transforms
  • Scroll animations: 700ms ease-out via FadeInSection

Spacing

  • Section padding: 120px vertical
  • Card padding: 24px (mobile) to 32px (desktop)
  • Grid gaps: 16px (tight), 24px (default), 32px (spacious)

Anti-Patterns

Don’tDo Instead
Build a custom modalUse @mantine/core Modal
Create a custom dropdownUse @mantine/core Select or Menu
Style with className="text-blue-500"Use c="blue.5" prop
Add !important to component CSSFix specificity or use CSS Modules
Use <div> for layoutUse Mantine’s Stack, Group, SimpleGrid, Flex
Create a custom tooltipUse @mantine/core Tooltip
Last updated on