These docs are a work in progress and may not be fully up to date. Some pages may contain internal notes for our team.
Skip to Content

Next.js — design system

The DropAFinder dashboard uses a custom SCSS design system — no Tailwind, no component library. Styles live in src/sass/ (globals) and in .module.scss files co-located with components. The visitor-facing finder widget has a separate token system defined per-finder via appearanceThemes.ts in the V2 builder config.

Token system

Tokens are CSS custom properties defined in src/sass/globals.scss. They are surfaced to SCSS as $v2-* variables via the bridge file src/sass/_v2-tokens.scss. The bridge pattern means tokens are defined once in :root/[data-theme] but can be used in CSS Modules (which can’t emit :root rules themselves).

Color tokens

All color tokens have a --v2- prefix. There are 34 tokens covering:

GroupTokens
Text--v2-text-1 (primary), --v2-text-2 (secondary), --v2-text-3 (tertiary), --v2-muted
Surfaces--v2-bg-page, --v2-surface, --v2-bg-raised, --v2-bg-subtle
Brand--v2-navy, --v2-navy-hover, --v2-blue, --v2-cyan, --v2-ink
Borders--v2-border, --v2-line
Tints--v2-navy-tint, --v2-navy-tint-hover, --v2-navy-light, --v2-blue-tint, --v2-cyan-dim
Status--v2-ok, --v2-warn, --v2-danger
Feedback--v2-success, --v2-success-bg, --v2-warning, --v2-warning-bg, --v2-error, --v2-error-bg

Use $v2-* SCSS variables in component files. Never hardcode hex values.

Spacing and layout tokens

Two layout utility properties on :root:

  • --app-pad — responsive outer padding (clamp(1.6rem, 1.2rem + 1.6vw, 3.2rem))
  • --app-gap — responsive gap between sections (clamp(1.2rem, 0.8rem + 1.2vw, 2.4rem))
  • --surface-radius — card/panel border-radius (1.4rem)
  • --surface-shadow — standard elevation shadow

Light / dark theming

The theme toggle is implemented with next-themes. It sets a data-theme attribute on <html>. The [data-theme='dark'] selector in globals.scss overrides all --v2-* custom properties with dark equivalents.

Light mode dark values map to #1A1D38 primary text and #F7F8FC page background. Dark mode inverts to #E8EAFF primary text and #0F1117 page background with rgba-based borders.

No JavaScript is needed to switch tokens — CSS handles the swap via the attribute selector. Components that need theme awareness can use useTheme() from next-themes for programmatic access.

SCSS file structure

FileContents
globals.scss:root + [data-theme='dark'] token definitions; imports all partials
_v2-tokens.scssBridge: SCSS $v2-* variables pointing to CSS custom properties
_colors.scssUtility color classes
_typography.scssBody, heading, label styles
_buttons.scss.btn, .btn-primary, .btn-secondary, etc.
_forms.scssInput, select, textarea, form group styles
_reset.scssCSS reset
_mixins.scssShared SCSS mixins (e.g., responsive breakpoints)
_settings.scssSCSS variables for breakpoints, spacing scale

Component styling pattern

  • CSS Modules (.module.scss) for component-scoped styles.
  • BEM class names inside modules.
  • Import the module and reference with styles['block__element'] or styles['block__element--modifier'].
  • Use clsx for conditional class combinations.
  • Access design tokens via $v2-* variables imported from _v2-tokens.scss.
@use '@/sass/v2-tokens' as *; .card { background: $v2-bg-raised; border: 1px solid $v2-border; border-radius: var(--surface-radius); } .card__title { color: $v2-text-1; }

Semi-transparent colors

When a dedicated token doesn’t exist for a transparency variant, use color-mix():

color: color-mix(in srgb, #{$v2-navy} 15%, transparent);