Material 3 (Material You) theme — cross-platform-consistent design system based on Google's Material Design 3 token specification.
Where Mob's other themes (Light, Dark, Birch, Citrus, Obsidian) pick colors and let each platform render with its own conventions, this theme overrides platform defaults so iOS and Android apps look the same: same color tokens, same typography scale, same shape system, same elevation rules.
When to use this
Use Material 3 when cross-platform visual consistency matters more than feeling native on each platform. iOS apps using this theme will look material-y rather than Apple-y — buttons get material shapes, type uses the material type scale, elevation is tonal-color overlay rather than iOS-style shadow.
Use one of the platform-respectful themes (Light, Dark) when native feel matters more than cross-platform parity.
Source
Token values are transcribed from Google's published Material 3
spec at https://m3.material.io/styles. The Compose Material 3
library (androidx.compose.material3) is the reference
implementation; this module mirrors its baseline color scheme +
type scale + shape system.
Usage
defmodule MyApp.App do
use Mob.App, theme: Mob.Theme.Material3
endOverride individual tokens:
use Mob.App, theme: {Mob.Theme.Material3, primary: 0xFFE91E63}What this maps onto Mob.Theme today
Mob.Theme's struct is smaller than the full M3 token surface
(M3 has tiered surface-container colors, an elevation scale,
a 5-tier type scale, a shape scale). For Phase 1 we map M3 tokens
onto the closest existing Mob.Theme fields and document the gaps
below. Phase 2 (visual fidelity) extends Mob.Theme's struct with
the missing fields and wires them through the renderer.
Today's mapping:
primary/on_primary— M3 primary (purple-ish baseline)secondary/on_secondary— M3 secondarybackground/on_background— M3 surface (light mode background)surface/on_surface— M3 surface-containersurface_raised— M3 surface-container-high (one tier up)muted— M3 on-surface-variantborder— M3 outline-varianterror/on_error— M3 errorradius_sm/_md/_lg/_pill— M3 shape scale extra-small, small, medium, full
Gaps (no field in Mob.Theme yet — Phase 2 work):
- Tonal-color elevation levels (M3 uses surface-color-at-elevation rather than shadows; needs new struct field)
- Surface-container-lowest / -low / -high / -highest tiers (currently collapsed to surface + surface_raised)
- Type scale (M3 has display-{l,m,s}, headline-{l,m,s},
title-{l,m,s}, body-{l,m,s}, label-{l,m,s} — 15 type roles;
Mob currently uses
type_scaleas a single multiplier) - Shape scale extra-large + extra-extra-large
- Motion duration + easing tokens
This module returns the closest-fit translation today; the visual polish round will fill in the gaps.
Summary
Functions
M3-spec tonal-elevation color stops, indexed by level (0-5).
M3 shape-scale corner radii (dp).
Returns the compiled Material 3 light theme struct.
M3 type-scale role definitions.
Functions
@spec elevation_color(0..5) :: non_neg_integer()
M3-spec tonal-elevation color stops, indexed by level (0-5).
Used by Phase 2 renderer integration to apply tonal overlay on surfaces — M3's analog to iOS shadow elevation. Each level adds more primary-color tint to the base surface.
Indexed by dp of "elevation": 0, 1, 3, 6, 8, 12. Returned as
the resolved color stop (already-blended primary-tinted surface).
Phase 2: wire this into the renderer for <Card> / <Box> with
material: :elevated so an elevated surface renders with the
correct tonal overlay rather than a fake shadow.
@spec shape(atom()) :: non_neg_integer()
M3 shape-scale corner radii (dp).
@spec theme() :: Mob.Theme.t()
Returns the compiled Material 3 light theme struct.
Dark variant lives in Mob.Theme.Material3.Dark.
@spec type_role(atom()) :: %{ size: number(), line_height: number(), weight: non_neg_integer() }
M3 type-scale role definitions.
Each role returns %{size: pt, line_height: pt, weight: integer}.
Phase 2: extend the renderer to accept a text_role: prop on
Text components that resolves through this table.