Typography Scale

Typography is the driving visual force of the mirror. We use Inter. Display headings use very thin weights to minimize light dispersion, while smaller labels use bold weights for legibility behind the reflective glass.

Display Extra Large (.display-xl / h1) 75px | Thin (100) | Tracking: -0.04em

08:32

<h1 class="display-xl">08:32</h1>
Display Large (.display-lg) 64px | Light (300) | Tracking: -0.02em
-14°C
<div class="display-lg">-14°C</div>
Headline Medium (.headline-md) 32px | Medium (500) | Tracking: 0
Stockholm
<div class="headline-md">Stockholm</div>
Body Base (.body-base) 20px | Regular (400) | Line-Height: 1.5
Main content paragraph or secondary temperature description.
<div class="body-base">Main content paragraph or secondary temperature description.</div>
Body Small (.body-sm) 16px | Regular (400) | Line-Height: 1.4
Details, metadata labels, or smaller paragraph blocks.
<div class="body-sm">Details, metadata labels, or smaller paragraph blocks.</div>
Module Header / Caps Label (.label-caps / h2 / .module-header) 14px (0.875rem) | Semi-Bold (600) | Uppercase | Tracking: 0.1em

Name Day

<h2 class="module-header">Name Day</h2>

Color Palette

The palette is strictly functional, optimized for light transmission through two-way glass. Every color has a defined purpose.

Core Mirror Palette CSS Custom Properties
The Void
--color-void: #000000 — Mandatory background. Absolute black for mirror invisibility.
High-Contrast White
--color-high-contrast: #ffffff — Primary data, time, headers.
Standard Gray
--color-standard-gray: #999999 — Body text, labels, secondary info.
Dimmed Charcoal
--color-dimmed-charcoal: #666666 — Borders, dividers, inactive elements.
Soft Ice Blue
--color-ice-blue: #cceeff — Cold / inactive data visualization accents.
Soft Rose Pink
--color-rose-pink: #ffccd5 — Warmth / urgent alert accents.
Status & Error Colors Functional Indicators
Status Online
--color-status-online: #a0ffba — Online / active / success.
Status Warning
--color-status-warning: #f87171 — Error / warning / offline.
Error
--color-error: #ffb4ab — Error text and alert titles.

Color Utility Classes

Colors have specific purposes to help prioritize readability against ambient lighting.

Color Aliases CSS Classes
.text-primary — High contrast data (#ffffff)
.text-secondary — Secondary information / labels (#999999)
.text-dimmed — Low contrast labels, inactive items (#666666)
.text-error — Error messages or warnings (#ffb4ab)
<span class="text-primary">Primary Light</span>
<span class="text-secondary">Standard gray label</span>
<span class="text-dimmed">Dimmed Charcoal</span>
<span class="text-error">Critical Error alert</span>

Layout & Grid Regions

The mirror viewport layout is constrained to a 3x3 peripheral grid. To preserve the functionality of the mirror reflection, content must remain at the edges, keeping the center empty unless displaying temporary modal alerts.

Valid Grid Regions (9 Positions) Peripheral Modular Grid
top_left
top_center
top_right
middle_left
middle_center
middle_right
bottom_left
bottom_center
bottom_right
<!-- Module position configuration in config.json -->
{
  "modules": {
    "mirrordash-clock": {
      "position": "top_left",
      "enabled": true
    }
  }
}
Flexbox Alignment Helpers (.flex-row, .flex-column, .flex-row-between, .flex-center) Zero-CSS Layout utilities
Horizontal Row (.flex-row) — aligns items and adds a standard gap:
22°C Sunny
Space Between (.flex-row-between) — labels left, values right:
Sensor status Online
Vertical Column (.flex-column) — stacks elements vertically:
Stockholm Heavy rain starting in 10 min
<!-- Horizontal Row with Icon alignment -->
<div class="flex-row">
    <i data-lucide="sun" class="text-primary"></i>
    <span class="body-base text-primary">22°C</span>
</div>

<!-- Space-Between row (left label, right value) -->
<div class="flex-row-between">
    <span class="text-secondary">Status</span>
    <span class="text-primary">Online</span>
</div>

<!-- Vertical Stack -->
<div class="flex-column">
    <span class="body-base text-primary">Title</span>
    <span class="body-sm text-secondary">Subtitle description...</span>
</div>

Iconography

The system uses Lucide Icons as its standard, vector-based line-art iconography. All icons inherit their parent element's text color and use a thin outline (default 1.5px stroke weight).

Recommended Weather Icons Lucide Icons
sun
cloud-sun
cloud
cloud-rain
cloud-lightning
snowflake
wind
Recommended Utility Icons Lucide Icons
wifi
wifi-off
award
settings
clock
calendar
alert-triangle
Markup Usage HTML snippet
<!-- Monochromatic line-art icons -->
<i data-lucide="sun"></i>
<i data-lucide="settings" class="text-secondary"></i>
<i data-lucide="alert-triangle" class="text-error glow"></i>

Containers & Depth

In a physical mirror, drop shadows are useless. Instead, we use semi-opaque dark backdrops to isolate content and subtle atmospheric glow filters to emphasize elements.

Module Container ([data-module]) Backdrop: rgba(0,0,0,0.93) | Radius: 4px | Padding: 16px

Demo Module

Content floats over mirror. Note the absence of boxy borders.
<div data-module="my-custom-module">
    <h2 class="module-header">Demo Module</h2>
    <div class="body-sm text-primary">Content goes here.</div>
</div>
Atmospheric Glow (.glow) Filter: drop-shadow(0 0 4px white(15%))
GLOWING TEXT
<div class="glow display-xl">GLOWING TEXT</div>
Backdrop Blur (.backdrop-blur-active) Critical Alert Focus Mode | blur(2px) brightness(50%)
Simulator:
Widget A
Widget B
<!-- Add class to body or container during critical alerts -->
<body class="backdrop-blur-active">
    <div data-module="weather">…</div>  <!-- blurred -->
    <div class="alert-modal">…</div>     <!-- stays sharp -->
</body>

UI Components

Pre-designed structural blocks for building clean, consistent mirror layouts.

Widget Header (.widget-header) Bottom underline divider

Weather Forecast

<div class="widget-header">
    <h2 class="module-header">Weather Forecast</h2>
</div>
Clock Module (display-xl + headline-md) DESIGN.md Centerpiece Pattern
08:32:45
<div style="display: flex; align-items: baseline;">
    <span class="display-xl">08:32</span>
    <span class="headline-md text-dimmed">:45</span>
</div>
Notification Card (.notification-card) Backdrop: rgba(0,0,0,0.93) | Radius: 16px (1rem) | Padding: 16px
System Update Available
Version 2.4.1 is ready to install. The mirror will restart automatically.
<div class="notification-card" data-module="notification">
    <div class="body-sm text-primary">System Update Available</div>
    <div class="body-sm text-secondary">Details here.</div>
</div>
Data Lists (.data-list) Clean Label/Value grids with online/warning deltas
SSE index 2,410.50 (+1.2%)
OMX Stockholm 960.20 (-0.8%)
System Load 0.12
<div class="data-list">
    <div class="data-list__item">
        <span class="data-list__label">SSE index</span>
        <span class="data-list__value data-list__value--up">2,410.50 (+1.2%)</span>
    </div>
    <div class="data-list__item">
        <span class="data-list__label">OMX Stockholm</span>
        <span class="data-list__value data-list__value--down">960.20 (-0.8%)</span>
    </div>
</div>
Status Indicators (.status-indicator) 8px colored inline dots
API Service Online
Database connection warning
<span class="status-indicator status-indicator--online"></span> Online
<span class="status-indicator status-indicator--warning"></span> Warning
Horizontal Separators (.separator-hr) 1px rule in dimmed charcoal
Block above separator

Block below separator
<hr class="separator-hr">
Carousel Containers (.carousel-group-container) Cross-fading overlapping slides
Simulator:
<div class="carousel-group-container">
    <div class="carousel-slide carousel-active" data-module="weather">
        <h2 class="module-header">Weather</h2>
        <div class="body-sm text-primary">Sunny, 22°C</div>
    </div>
    <div class="carousel-slide" data-module="news">
        <h2 class="module-header">News Feed</h2>
        <div class="body-sm text-secondary">Headlines...</div>
    </div>
</div>

Extended Layout Elements

Comprehensive, layout-ready widgets and telemetry patterns to simplify building common dashboard modules.

Weather Forecast Grid (.forecast-grid) Horizontal Forecast Rows
Mon 22°14°
Tue 20°12°
Wed 16°10°
Thu 18°11°
Fri 24°15°
<div class="forecast-grid">
    <div class="forecast-grid__day">
        <span class="forecast-grid__name">Mon</span>
        <i data-lucide="sun" class="forecast-grid__icon"></i>
        <span class="forecast-grid__temp">22°<span class="forecast-grid__temp-low">14°</span></span>
    </div>
    <div class="forecast-grid__day">
        <span class="forecast-grid__name">Tue</span>
        <i data-lucide="cloud-sun" class="forecast-grid__icon"></i>
        <span class="forecast-grid__temp">20°<span class="forecast-grid__temp-low">12°</span></span>
    </div>
</div>
Agenda / Schedule Lists (.agenda-list) Calendar Event Layouts
Jun 02
Design Sync Meeting 09:00 - 10:30 | Room 404
Jun 04
Product Launch Dinner 18:00 - 21:00 | Grand Hotel
<div class="agenda-list">
    <div class="agenda-list__item">
        <div class="agenda-list__date">
            <span class="agenda-list__date-month">Jun</span>
            <span class="agenda-list__date-day">02</span>
        </div>
        <div class="agenda-list__details">
            <span class="agenda-list__title">Design Sync Meeting</span>
            <span class="agenda-list__subtitle">09:00 - 10:30 | Room 404</span>
        </div>
    </div>
</div>
Progress & Gauge Bars (.gauge-bar) Visual Telemetry Gauges
System Storage 65%
<div class="gauge-bar">
    <div class="gauge-bar__label-row">
        <span>System Storage</span>
        <span>65%</span>
    </div>
    <div class="gauge-bar__track">
        <div class="gauge-bar__fill" style="width: 65%;"></div>
    </div>
</div>
Stats Grid (.stats-grid) Visual Dash Grid telemetry
0.12 Load
42° Temp
1.2G RAM
<div class="stats-grid">
    <div class="stats-grid__item">
        <span class="stats-grid__value">0.12</span>
        <span class="stats-grid__label">Load</span>
    </div>
    <div class="stats-grid__item">
        <span class="stats-grid__value">42°</span>
        <span class="stats-grid__label">Temp</span>
    </div>
    <div class="stats-grid__item">
        <span class="stats-grid__value">1.2G</span>
        <span class="stats-grid__label">RAM</span>
    </div>
</div>
Alert Callout Banners (.alert-callout) Critical Warn Indicators
Warning
The back door has been left open for 10 minutes.
<div class="alert-callout">
    <div>
        <div class="alert-callout__title">Warning</div>
        <div class="alert-callout__desc">The back door has been left open for 10 minutes.</div>
    </div>
</div>

Configuration Form Controls

MirrorDash auto-generates admin settings forms from each module's config_schema.json. The form generator reads standard JSON Schema properties and picks the correct input control automatically. Below are all supported field types — copy the schema snippet into your module's config_schema.json to get the rendered control.

Text Input type: string

The city name to display weather for.

"city": {
  "type": "string",
  "title": "City",
  "description": "The city name to display weather for.",
  "default": "Stockholm"
}
Toggle Switch type: boolean

Display seconds in the clock readout.

"show_seconds": {
  "type": "boolean",
  "title": "Show Seconds",
  "description": "Display seconds in the clock readout.",
  "default": true
}
Number Input type: integer / number

Maximum number of calendar events to show.

"max_events": {
  "type": "integer",
  "title": "Max Events",
  "description": "Maximum number of calendar events to show.",
  "default": 10
}
Range Slider type: integer / number + minimum + maximum

Screen backlight brightness level (10–100%).

85
"brightness": {
  "type": "integer",
  "title": "Brightness",
  "description": "Screen backlight brightness level (10–100%).",
  "minimum": 10,
  "maximum": 100,
  "default": 85
}
Dropdown Select type: string + enum

Display language for labels and dates.

"language": {
  "type": "string",
  "title": "Language",
  "description": "Display language for labels and dates.",
  "enum": ["sv", "en"],
  "default": "sv"
}
Multi-select Checkboxes type: array + items.enum

Select one or more preconfigured news sources.

"builtin_feeds": {
  "type": "array",
  "title": "Built-in Feeds",
  "description": "Select one or more preconfigured news sources.",
  "items": {
    "type": "string",
    "enum": ["bbc_news", "sr_ekot", "cnn_edition"]
  },
  "default": ["bbc_news"]
}
Dynamic Object List type: array + items.type: object

Allows administrators to manage a list of structured items. Each item is rendered inside an expandable card. The layout features built-in controls to re-order items (Move Up / Move Down buttons) and delete entries dynamically.

Dynamic Sub-field Types & Naming Conventions:

  • Color Swatches: A property named exactly "color" triggers a grid of preset swatches (White, Ice Blue, Rose Pink, Green, Red, Gray, Charcoal) along with a text box for custom Hex/CSS values.
  • Icon Picker: A property named exactly "icon" or ending in "_icon" renders a visual grid of outline icon picker buttons (Calendar, Clock, Home, etc.) plus a text box for custom Lucide icon keywords.
  • Dropdown Selection: Any property defining an "enum" array of options automatically renders as a selection dropdown (<select>) instead of a text entry box.
  • Default Inputs: All other schema properties of type "string", "number", or "integer" default to standard text input fields.

A list of devices to display with specific styling.

"entities": {
  "type": "array",
  "title": "Tracked Entities",
  "description": "Configure a list of devices to display.",
  "items": {
    "type": "object",
    "title": "Entity",
    "properties": {
      "entity_id": {
        "type": "string",
        "title": "Entity ID",
        "description": "The full Home Assistant entity ID."
      },
      "layout": {
        "type": "string",
        "title": "Layout Style",
        "default": "compact",
        "enum": ["detailed", "compact"]
      },
      "custom_icon": {
        "type": "string",
        "title": "Custom Icon"
      },
      "color": {
        "type": "string",
        "title": "Indicator Color",
        "default": "#ffffff"
      }
    },
    "required": ["entity_id"]
  },
  "default": []
}
Nested Object (Accordion) type: object
Advanced Settings

Fine-grained options for advanced users.

"advanced": {
  "type": "object",
  "title": "Advanced Settings",
  "description": "Fine-grained options for advanced users.",
  "properties": {
    "timeout": {
      "type": "integer",
      "title": "Timeout",
      "default": 30
    }
  }
}
Color Picker type: string + format: color (or key named "color")

Override the primary highlight color.

"accent_color": {
  "type": "string",
  "format": "color",
  "title": "Accent Color",
  "description": "Override the primary highlight color.",
  "default": "#ffffff"
}
Password / API Key type: string + format: password (or key: api_key / token / secret)

Your service API key. Stored locally only.

"api_key": {
  "type": "string",
  "format": "password",
  "title": "API Key",
  "description": "Your service API key. Stored locally only.",
  "default": ""
}
Textarea type: string + format: textarea (or key: description / message / text)

Text to show as the welcome message.

"message": {
  "type": "string",
  "format": "textarea",
  "title": "Greeting Message",
  "description": "Text to show as the welcome message.",
  "default": "Good morning!"
}

System & Connection Status

System-level indicators displayed at the top-center to show connection statuses. Use the buttons below to preview the states.

WebSocket Status Pill (.ws-status) Interactive States
Simulator:
Connecting…
<div class="ws-status ws-status--connecting">
    <span class="ws-status__dot"></span>
    <span class="ws-status__label">Connecting…</span>
</div>

Module Loading Skeletons

Visual skeletons displayed on page load before WebSocket messages populate data. Click "Simulate Load Done" to see the fade-in and slide entrance animation.

Module Loading Placeholder (.module-loading-placeholder) Interactive Simulator
Loading Swedish Name Day…
<!-- Pre-rendered loading state -->
<div data-module="mirrordash_namnsdag" class="module-loading-placeholder">
    <div class="module-loading-content">
        <span class="module-loading-spinner"></span>
        <span class="module-loading-text">Loading Swedish Name Day…</span>
    </div>
</div>