Skip to content

Creator Hub — Design System

Link-in-bio platform design system. Mobile-first, 375px minimum. Tailwind CSS + vanilla HTML/JS. Competitors studied: Beacons.ai, Linktree, Stan Store, Koji, Carrd.


1. Color Palette

Brand Tokens

Token Hex Tailwind Custom Usage
--color-primary #6C47FF primary CTAs, active states, brand accent
--color-primary-hover #5535E0 primary-hover Button hover
--color-primary-light #EEE9FF primary-light Tinted backgrounds, pills
--color-secondary #FF6B6B secondary Social link accents, tips/payments
--color-accent #00D4AA accent Success emphasis, live indicators
--color-surface #FFFFFF surface Cards, modals, inputs
--color-bg #F7F7FB bg Page background
--color-border #E4E4F0 border-base Dividers, input outlines
--color-text-primary #1A1A2E text-primary Headings
--color-text-secondary #6B6B8A text-secondary Body, labels
--color-text-muted #A5A5C0 text-muted Captions, placeholders

Semantic Tokens

Token Hex Usage
--color-success #00D4AA Checkmarks, publish confirmed
--color-success-bg #E6FAF6 Toast bg, status chips
--color-error #FF4D6A Validation errors, delete actions
--color-error-bg #FFF0F3 Error toast bg
--color-warning #FFB020 Unsaved changes, quota warnings
--color-warning-bg #FFF8E6 Warning toast bg

Dark Theme Overrides (see Section 6 for full token map)

Primary brand purple holds in dark mode. Backgrounds invert to #0E0E1A (page) and #1A1A2E (surface).


2. Typography

Font Stack

--font-heading: 'Plus Jakarta Sans', system-ui, sans-serif;
--font-body:    'Inter', system-ui, sans-serif;
--font-mono:    'JetBrains Mono', 'Fira Code', monospace;

Google Fonts import:

<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@600;700;800&family=Inter:wght@400;500;600&display=swap" rel="stylesheet">

Scale

Role Size Weight Line-height Tailwind classes
display clamp(40px, 8vw, 64px) 800 1.1 text-5xl lg:text-7xl font-extrabold
h1 clamp(32px, 5vw, 48px) 700 1.2 text-4xl lg:text-5xl font-bold
h2 clamp(24px, 4vw, 36px) 700 1.25 text-3xl lg:text-4xl font-bold
h3 24px 600 1.3 text-2xl font-semibold
h4 20px 600 1.35 text-xl font-semibold
body-lg 18px 400 1.6 text-lg font-normal
body 16px 400 1.6 text-base font-normal
body-sm 14px 400 1.5 text-sm font-normal
caption 12px 500 1.4 text-xs font-medium
label 13px 600 1.3 text-[13px] font-semibold
mono 13px 400 1.5 text-[13px] font-mono

3. Spacing Scale

Base unit: 4px

Token px Tailwind
space-1 4px p-1 / m-1
space-2 8px p-2 / m-2
space-3 12px p-3 / m-3
space-4 16px p-4 / m-4
space-5 20px p-5 / m-5
space-6 24px p-6 / m-6
space-8 32px p-8 / m-8
space-10 40px p-10 / m-10
space-12 48px p-12 / m-12
space-16 64px p-16 / m-16
space-20 80px p-20 / m-20

4. Component Inventory

4.1 Buttons

Primary Button

bg: --color-primary (#6C47FF)
text: white, 14px font-semibold
padding: 12px 24px (py-3 px-6)
border-radius: 10px (rounded-[10px])
shadow: 0 4px 14px rgba(108,71,255,0.35)
hover: bg --color-primary-hover, shadow intensifies (0 6px 20px rgba(108,71,255,0.45))
active: scale(0.97), shadow reduced
disabled: opacity-40, cursor-not-allowed
transition: all 150ms ease

Secondary Button

bg: white
text: --color-primary, 14px font-semibold
border: 1.5px solid --color-primary
padding: 11px 24px (compensate for border)
border-radius: 10px
hover: bg --color-primary-light
active: scale(0.97)
shadow: none

Ghost Button

bg: transparent
text: --color-text-secondary, 14px font-medium
border: 1.5px solid --color-border
padding: 11px 20px
border-radius: 10px
hover: bg --color-bg, text --color-text-primary
active: scale(0.97)

Danger Button

bg: --color-error (#FF4D6A)
text: white, 14px font-semibold
padding: 12px 24px
border-radius: 10px
shadow: 0 4px 14px rgba(255,77,106,0.3)
hover: bg #E83055

Icon Button (square)

size: 40px x 40px
bg: --color-bg
border: 1.5px solid --color-border
border-radius: 10px
icon: 18px, --color-text-secondary
hover: bg white, border-color --color-primary, icon color --color-primary

4.2 Cards

Base Card

bg: white
border: 1px solid --color-border
border-radius: 16px (rounded-2xl)
padding: 24px (p-6)
shadow: 0 1px 4px rgba(0,0,0,0.06)
hover (interactive): shadow 0 8px 24px rgba(0,0,0,0.10), translateY(-2px)
transition: all 200ms ease
bg: white
border: none
border-radius: 14px
padding: 16px 20px
shadow: 0 2px 8px rgba(0,0,0,0.08)
hover: shadow 0 6px 20px rgba(0,0,0,0.12), translateY(-1px)
height: min 60px
layout: flex, items-center, gap-3
left: 40px icon area (optional)
center: title (16px semibold), subtitle (13px muted)
right: chevron icon 16px

Stat Card (dashboard)

bg: white
border: 1px solid --color-border
border-radius: 16px
padding: 20px 24px
layout: flex-col gap-1
label: 12px font-medium text-muted uppercase tracking-wide
value: 32px font-bold text-primary
delta: 13px, green/red pill with arrow

Embed Block Card

bg: --color-bg
border: 1px solid --color-border
border-radius: 14px
overflow: hidden
header: 48px, platform icon + title + collapse button
body: aspect-video for video, auto for others
padding: 0 (content bleeds to edges)

4.3 Input Fields

Text Input

height: 44px
padding: 0 14px
bg: white
border: 1.5px solid --color-border
border-radius: 10px
font: 15px, --color-text-primary
placeholder: --color-text-muted
focus: border-color --color-primary, box-shadow 0 0 0 3px rgba(108,71,255,0.15)
error: border-color --color-error, box-shadow 0 0 0 3px rgba(255,77,106,0.12)
disabled: bg --color-bg, opacity 0.6
transition: border-color 150ms, box-shadow 150ms

Textarea

Same as text input but:
padding: 12px 14px
min-height: 96px
resize: vertical

Input with Prefix/Suffix

wrapper: flex, border 1.5px solid --color-border, border-radius 10px
prefix: 44px wide, bg --color-bg, border-right 1px --color-border, text-muted centered
input: flex-1, border 0, focus: no shadow on input (shadow on wrapper)
suffix: same as prefix, border-left instead

Select / Dropdown

Same as text input
appearance: none
background-image: chevron SVG right 14px
padding-right: 40px

4.4 Toggle

track: 44px x 24px, border-radius 12px
bg off: --color-border
bg on: --color-primary
thumb: 20px circle, white, shadow 0 1px 3px rgba(0,0,0,0.2)
thumb position off: translateX(2px)
thumb position on: translateX(22px)
transition: background 200ms, transform 200ms
focus-visible: outline 2px --color-primary, outline-offset 2px

4.5 Avatar

Sizes:
  xs: 24px
  sm: 32px
  md: 48px
  lg: 64px
  xl: 96px
  2xl: 128px

Shape: circle (rounded-full)
Border: 2px solid white
Shadow: 0 2px 8px rgba(0,0,0,0.12)
Fallback: gradient bg using primary + secondary, initials in white 

Profile hero avatar: 96px with 3px gradient ring (primary → secondary) as border, gap 2px white inset

height: 36px
padding: 0 14px
border-radius: 999px (rounded-full)
bg: platform-specific (see below) or --color-primary-light
icon: 16px, left-aligned, gap 8px
text: 13px font-semibold
hover: brightness(1.08), scale(1.02)

Platform colors:
  Instagram: linear-gradient(135deg, #833AB4, #FD1D1D, #F77737)
  TikTok: #010101
  YouTube: #FF0000
  Twitter/X: #000000
  LinkedIn: #0A66C2
  Spotify: #1DB954
  Twitch: #9146FF
  Discord: #5865F2
  GitHub: #24292F
  Custom: --color-primary

4.7 Sidebar Nav

width: 240px (desktop), full-screen overlay (mobile)
bg: white
border-right: 1px solid --color-border
padding: 16px 12px

Nav item:
  height: 40px
  padding: 0 12px
  border-radius: 8px
  icon: 18px, gap 10px
  text: 14px font-medium text-secondary
  hover: bg --color-bg, text-primary
  active: bg --color-primary-light, text --color-primary, icon color primary, font-semibold

Section label:
  10px font-semibold text-muted uppercase tracking-widest
  padding: 8px 12px
  margin-top: 16px

4.8 Modal

Overlay: rgba(0,0,0,0.5) backdrop-blur-sm
Container:
  bg: white
  border-radius: 20px
  padding: 0
  width: min(520px, calc(100vw - 32px))
  max-height: calc(100vh - 64px)
  overflow-y: auto
  shadow: 0 24px 64px rgba(0,0,0,0.18)

Header:
  padding: 24px 24px 0
  layout: flex justify-between items-center
  title: h3
  close: icon-button (32px variant)

Body:
  padding: 20px 24px

Footer:
  padding: 0 24px 24px
  layout: flex gap-3 justify-end
  border-top: 1px solid --color-border (if content scrolls)

Animation:
  enter: fade + scale(0.95 → 1) 200ms ease-out
  exit: fade + scale(1 → 0.97) 150ms ease-in

4.9 Toast Notification

position: fixed, bottom 24px right 24px (mobile: bottom 16px, full-width minus 16px margin)
width: 360px (mobile: 100%)
border-radius: 14px
padding: 14px 16px
shadow: 0 8px 32px rgba(0,0,0,0.14)
layout: flex, gap 12px, items-start

Icon area: 20px icon, colored per type
Content: title 14px semibold + body 13px text-secondary
Dismiss: 16px x icon, top-right

Variants:
  success: left-border 4px --color-success, icon-bg --color-success-bg
  error:   left-border 4px --color-error,   icon-bg --color-error-bg
  warning: left-border 4px --color-warning, icon-bg --color-warning-bg
  info:    left-border 4px --color-primary,  icon-bg --color-primary-light

Animation:
  enter: translateX(110%) → translateX(0) 300ms spring
  exit:  translateX(0) → translateX(110%) 200ms ease-in
Auto-dismiss: 4000ms, progress bar optional

5. Page Wireframes (Structured Text)

5.1 Public Profile Page

Viewport: 375px mobile, max-width 480px centered (not full-bleed)

┌─────────────────────────────────┐
│  THEME HEADER                   │  ← full-width, height 180px
│  gradient/image background      │    theme color bleeds to top of screen
│                                 │
│         [AVATAR 96px]           │  ← centered, overlaps into content area
└─────────────────────────────────┘
┌─────────────────────────────────┐
│  [Name h2]                      │  ← text-center, mt-12 (for avatar overlap)
│  [Username @handle caption]     │
│  [Bio body-sm text-secondary]   │  ← max 160 chars, 3-line clamp
│                                 │
│  [Social Pills row, scroll x]   │  ← horizontal scroll on mobile
│  IG  TK  YT  TW  SP             │
│                                 │
│  ── LINK BLOCKS ────────────────│  ← full-width cards, 12px gap
│  [Link Card 1]                  │
│  [Link Card 2]                  │
│  [Embed Card - YouTube]         │
│  [Email Capture Card]           │
│  [Tip Jar Card]                 │
│  [Scheduling Card]              │
│  ...                            │
│                                 │
│  [Powered by Creator Hub]       │  ← 12px caption, bottom 16px, centered
└─────────────────────────────────┘

Desktop (640px+): max-width 480px, centered horizontally, sidebar hidden (profile is standalone).

Key layout decisions: - Avatar overlaps hero by 48px (negative margin-top on content area) - Link blocks are full-width within the 480px container, no side-by-side columns - Embed blocks auto-expand inline, no modal - Theme color applies to hero + link block accents + CTA buttons


5.2 Dashboard / Analytics Page

Full app layout: sidebar 240px (desktop) + main content area

[SIDEBAR]                    [MAIN CONTENT]
  Logo                       ┌────────────────────────────────────────┐
  ─────                      │ Page header: "Analytics"  [Date range] │
  Overview         ◀ active  ├────────────────────────────────────────┤
  Editor                     │ STAT CARDS ROW (4 cards, responsive)   │
  Appearance                 │  Views  |  Clicks  |  CTR  |  Earnings │
  Settings                   ├────────────────────────────────────────┤
  ─────                      │ TIME-SERIES CHART (full-width)          │
  Domains                    │  line chart, 30-day default             │
  Billing                    │  hover tooltip with date/values         │
  ─────                      ├────────────────────────────────────────┤
  [Avatar] Justin            │ TWO-COL: [Top Links table] [Referrers] │
  @handle                    │                                         │
  [Signout]                  │  link title | clicks | %bar            │
                             │  ─────────────────────────────────────  │
                             │  source | visits | %                   │
                             ├────────────────────────────────────────┤
                             │ DEVICE BREAKDOWN (donut + legend)       │
                             └────────────────────────────────────────┘

Mobile: Sidebar collapses to bottom tab bar (5 icons). Stat cards stack 2x2. Charts full-width. Tables become cards.


5.3 Block Editor Page

Full app layout: sidebar + editor canvas + properties panel

[SIDEBAR 240px]   [CANVAS 480px max centered]   [PROPERTIES PANEL 280px]
  Block Library    ┌────────────────────────┐     [Context-sensitive]
  ─────────────    │ PROFILE PREVIEW HEADER │     
  + Link           │  [Avatar + Name]       │     When block selected:
  + Header         │  [Bio]                 │       Block type label
  + Embed          │  [Social pills]        │       ─────────────────
  + Email Capture  ├────────────────────────┤       [Title input]
  + Scheduling     │ ▓▓ LINK BLOCK ◀drag   │       [URL input]
  + Tip Jar        │    "My Website"        │       [Icon picker]
  + Spacer         │ ────────────────────── │       [Visible toggle]
  + Divider        │ ▒▒ HEADER BLOCK        │       [Schedule toggle]
  ─────────────    │    "Shop Now ↓"        │       ─────────────────
  Saved Blocks     │ ────────────────────── │       [Delete block]
                   │ ▒▒ EMBED BLOCK         │
                   │    YouTube [thumbnail] │     When nothing selected:
                   │ ────────────────────── │       Page settings
                   │ [+ Add block] button   │       Theme picker
                   └────────────────────────┘       SEO settings
                        ↑ live preview
                      of public profile

Drag handle: left edge of each block, 4px wide drag zone, 20px handle icon on hover. Block selection: click → 2px primary border around block, properties panel updates. Mobile editor: single column, properties panel slides up as bottom sheet.


5.4 Landing / Signup Page

No sidebar. Full-bleed marketing layout.

[NAV]
  Logo (left)                    [Sign In]  [Get Started →]

[HERO SECTION]  full-height viewport
  headline (display clamp): "Your entire brand, one link."
  subhead (body-lg): "Launch your page in 2 minutes..."
  [CTA button primary: Get Started Free]
  [Ghost: See example →]

  hero visual: mockup of profile page on phone (right, desktop) 
               or below headline (mobile)

[SOCIAL PROOF BAR]
  "Trusted by 10,000+ creators"  |  star ratings  |  logos

[FEATURES GRID]
  3-col (desktop) / 1-col (mobile)
  Each: icon (48px) + h4 + body-sm
  Features: Custom Domain, Analytics, Embed Content, Email Capture, 
            Payments, Drag-Drop Editor, Custom Themes, SEO

[COMPARISON TABLE]
  Creator Hub vs Linktree vs Beacons
  rows: price, custom domain, analytics depth, embeds, payments, 
        email capture, scheduling

[THEME SHOWCASE]
  horizontal scroll gallery of 6 preset themes

[TESTIMONIALS]
  3-card grid, avatar + quote + name + handle

[PRICING]
  3 cards: Free / Pro ($9/mo) / Business ($29/mo)
  primary card = Pro (elevated, purple border)

[SIGNUP FORM]
  email input + [Create Free Account] centered, max-width 480px

[FOOTER]
  4-col links + social icons + copyright

6. Theme System

Token Architecture

Two layers: global (palette, never used directly in components) and semantic (what components reference).

:root {
  /* Spacing */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-6: 24px;
  --space-8: 32px;
  --space-12: 48px;

  /* Radius */
  --radius-sm: 6px;
  --radius-md: 10px;
  --radius-lg: 14px;
  --radius-xl: 16px;
  --radius-2xl: 20px;
  --radius-full: 9999px;

  /* Shadows */
  --shadow-sm: 0 1px 4px rgba(0,0,0,0.06);
  --shadow-md: 0 4px 14px rgba(0,0,0,0.08);
  --shadow-lg: 0 8px 32px rgba(0,0,0,0.12);
  --shadow-xl: 0 24px 64px rgba(0,0,0,0.18);
  --shadow-primary: 0 4px 14px rgba(108,71,255,0.35);
}

Light Theme (default)

[data-theme="light"], :root {
  --color-bg: #F7F7FB;
  --color-surface: #FFFFFF;
  --color-surface-2: #F0F0F8;
  --color-border: #E4E4F0;
  --color-text-primary: #1A1A2E;
  --color-text-secondary: #6B6B8A;
  --color-text-muted: #A5A5C0;
  --color-primary: #6C47FF;
  --color-primary-hover: #5535E0;
  --color-primary-light: #EEE9FF;
  --color-secondary: #FF6B6B;
  --color-accent: #00D4AA;
}

Dark Theme

[data-theme="dark"] {
  --color-bg: #0E0E1A;
  --color-surface: #1A1A2E;
  --color-surface-2: #242438;
  --color-border: #2E2E4A;
  --color-text-primary: #F0F0F8;
  --color-text-secondary: #9090B8;
  --color-text-muted: #5A5A7A;
  --color-primary: #7C5CFF;          /* slightly lighter for dark bg contrast */
  --color-primary-hover: #6C47FF;
  --color-primary-light: #2A2044;
  --color-secondary: #FF7B7B;
  --color-accent: #00E4BC;
  --shadow-sm: 0 1px 4px rgba(0,0,0,0.3);
  --shadow-md: 0 4px 14px rgba(0,0,0,0.4);
  --shadow-lg: 0 8px 32px rgba(0,0,0,0.5);
}

Profile Page Themes (user-selectable)

Each profile theme overrides hero bg and link-block accent color only. App chrome stays in system theme.

Theme Name Hero BG Link Block Text on Hero
aurora linear-gradient(135deg, #6C47FF, #FF6B6B) white white
midnight #0E0E1A #1A1A2E white
cotton #FFF0F5 white #1A1A2E
forest linear-gradient(135deg, #134E4A, #065F46) white/translucent white
paper #FFFEF7 #FFFFF0 #1A1A2E
carbon #111111 #1C1C1C white

7. Breakpoints

screens: {
  'sm':  '640px',   // large phones, small tablets (landscape)
  'md':  '768px',   // tablets
  'lg':  '1024px',  // small laptops, iPad Pro
  'xl':  '1280px',  // standard desktop
}

Mobile-first patterns: - Grid: grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 - Sidebar: hidden on mobile (bottom tab bar), lg:flex for sidebar - Profile canvas: max-w-[480px] mx-auto w-full - Analytics stat cards: grid grid-cols-2 lg:grid-cols-4 - Typography: all heading sizes use clamp() to avoid breakpoint jumps


8. Tailwind Config Addons

// tailwind.config.js additions
module.exports = {
  theme: {
    extend: {
      colors: {
        primary: {
          DEFAULT: '#6C47FF',
          hover: '#5535E0',
          light: '#EEE9FF',
        },
        secondary: '#FF6B6B',
        accent: '#00D4AA',
        surface: '#FFFFFF',
        'bg-base': '#F7F7FB',
        'border-base': '#E4E4F0',
        'text-primary': '#1A1A2E',
        'text-secondary': '#6B6B8A',
        'text-muted': '#A5A5C0',
      },
      fontFamily: {
        heading: ['Plus Jakarta Sans', 'system-ui', 'sans-serif'],
        body:    ['Inter', 'system-ui', 'sans-serif'],
        mono:    ['JetBrains Mono', 'Fira Code', 'monospace'],
      },
      borderRadius: {
        '4xl': '2rem',
      },
      boxShadow: {
        'primary': '0 4px 14px rgba(108,71,255,0.35)',
        'primary-lg': '0 6px 20px rgba(108,71,255,0.45)',
      },
      maxWidth: {
        'profile': '480px',
      },
    },
  },
}

9. Motion Defaults

All interactive elements use transition-all duration-150 ease-out as default. Elevation lifts use duration-200. Modal/drawer animations use duration-300. Respect prefers-reduced-motion: wrap entrance animations in a media query check.

@media (prefers-reduced-motion: reduce) {
  * { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }
}