Docs :: Default Theme
| File name | Description | Source |
|---|---|---|
theme.default.css |
Default theme entry: imports the next two | Github |
theme.default.tokens.css |
Raw tokens: colors, type, spacing, etc. | Github |
theme.default.ui.css |
UI tokens: what elements and components use | Github |
theme.starter.css |
Use it as a start for your own theme | Github |
theme.wireframe.css |
Full swappable theme example | Github |
Every design value in mCSS (colors, fonts, spacing, component styling) lives in the default theme. Your own theme should be imported after it and just override what it needs.
Never edit the default theme files. Keep your design decisions in your own theme, so updating the framework is easy.
Activating a theme
Activate the default theme right after the framework, then (optionally) your own theme:
@import url(./framework/mcss.css);@import url(./framework/mcss.components.css); /* optional */@import url(./framework/theme.default.css);@import url(./site/theme.starter.css); /* your theme */Theme files are self-layered and your theme goes in the theme.user layer:
@layer theme.user { /* […] */}mCSS is set up so that, regardless of how you load your theme (@import, <link>, or bundler), it always overrides the default theme.
Writing your own theme
Copy theme.starter.css and start overriding:
- Tokens first. Most themes never need a selector: raw tokens for the palette and type, UI tokens for general UI changes, and component tokens for details.
- Style rules only for what tokens can’t express: pseudo-elements,
nth-childrhythm, font smoothing,text-wrap, etc. Your theme file is the one place where overriding framework classes and HTML elements from other files is ok. - Check tokens before writing a style rule. The page is already painted from
--body-background-color,--text-color, and--text: set those instead of writing abodyrule for background, color, or font. - No
!important. It will break the layer system. And if you need!important, it’s a sign you’re doing something wrong.
Full themes
A theme can also be a complete, distributable style. mCSS ships with the theme.wireframe.css example. (Flip the switcher on the marketing template to see it live.)
A full theme is an entry that imports the default theme itself and overrides on top, so you activate it INSTEAD of the default:
@import url(./framework/mcss.css);/* theme.default.css is swapped */@import url(./framework/theme.wireframe.css);The wireframe file is a good read if you’re planning a full theme. Token overrides do most of the work (grayscale palette, handwriting font stack, “paper cutout” shadows), a few style rules cover the rest (wavy underlines, tilted cards), and it’s deliberate about what it leaves alone: the focus ring stays crisp, and text stays high-contrast.
Tokens
Tokens are CSS custom properties, split in two files:
- Raw tokens are named for what they are: raw values like colors, type sizes, spacing, radii, etc.
- UI tokens are named for what they’re for: they map raw tokens to elements and components.
Because components read var(--ui-border-color) instead of a raw hex value, one override can have three levels of blast radius:
@layer theme.user { :root { /* Whole palette shifts */ --base-950: #1a1208;
/* Every bordered surface at once */ --ui-border-color: light-dark(var(--base-300), var(--base-600));
/* Single component override */ --bt-border-radius: 0; }}That’s why small theme files can go far with a handful of token overrides.
How to use tokens
When you start a new project, put your design’s raw token values in your own theme: your base and primary colors, your font stacks, and whatever else your design calls for. The defaults are sensible and things like spacing might not need to change.
Then continue overriding UI tokens provided by mCSS as you go, and creating your own when needed. Do not add hard-coded “magic numbers” anywhere else but in your theme’s tokens.
UI tokens
UI tokens are named for what they’re for: semantic aliases (--ui-border-color), element defaults (--heading-font, --input-padding, etc.), and every component’s defaults (--badge-color, --card-spacing, etc.).
A UI token usually takes another token for value: a UI token when the meaning is shared (--input-border-color is --ui-border-color), or a raw token when the value should stay in sync with the rest of the design (--fieldset-padding is --sm3). Hard-coded values are for the few places where that sync would be wrong: content (separator strings, icon URLs), geometry tuned to one control (--toggle-width), and element-relative em measures.
For your own components, there’s no hard and fast rule about which kind of token to use. If the same style comes up in several places with the same meaning, a new UI token is probably the best option.
Raw tokens
Color
Check out tints.dev if you want to make your own palettes programmatically.
Base
| Token | Value | Demo |
|---|---|---|
base-0 |
#fff | |
base-50 |
#f6f7f9 | |
base-100 |
#edeef1 | |
base-200 |
#d6dbe1 | |
base-300 |
#b2bbc7 | |
base-400 |
#8897a8 | |
base-500 |
#697a8e | |
base-600 |
#546375 | |
base-700 |
#4a5666 | |
base-800 |
#3c4550 | |
base-900 |
#353c45 | |
base-950 |
#23282e |
Primary
| Token | Value | Demo |
|---|---|---|
primary-50 |
#f0f9ff | |
primary-100 |
#e0f2fe | |
primary-200 |
#bae6fd | |
primary-300 |
#7dd3fc | |
primary-400 |
#38bdf8 | |
primary-500 |
#0ea5e9 | |
primary-600 |
#0284c7 | |
primary-700 |
#0369a1 | |
primary-800 |
#075985 | |
primary-900 |
#0c4a6e | |
primary-950 |
#082f49 |
Feedback
| Token | Value | Demo |
|---|---|---|
yes-100 |
#d5f6e8 | |
yes-200 |
#afebd4 | |
yes-300 |
#7adbbd | |
yes-400 |
#46c4a0 | |
yes-500 |
#13886d | |
no-100 |
#ffe4e6 | |
no-200 |
#fecdd3 | |
no-300 |
#fda4af | |
no-400 |
#fb7185 | |
no-500 |
#e11d48 | |
maybe-100 |
#fff7d6 | |
maybe-200 |
#fff0b3 | |
maybe-300 |
#ffd64a | |
maybe-400 |
#ffc220 | |
maybe-500 |
#f9a007 |
Highlight
The text marker color, consumed by the --marker-color UI token (what <mark> uses). Override --highlight-500 in a theme to restyle every highlight.
| Token | Value | Demo |
|---|---|---|
highlight-500 |
#ffee00 |
Dimension
Dimension tokens can be used anywhere you need to set margin, padding, width, height, etc.
| Token | Value | Demo |
|---|---|---|
xs1 |
4px | |
xs2 |
8px | |
xs3 |
12px | |
sm1 |
16px | |
sm2 |
20px | |
sm3 |
24px | |
md1 |
28px | |
md2 |
32px | |
md3 |
36px | |
lg1 |
40px | |
lg2 |
44px | |
lg3 |
48px | |
xl1 |
56px | |
xl2 |
64px | |
xl3 |
80px | |
xxl1 |
96px | |
xxl2 |
112px | |
xxl3 |
128px | |
mega1 |
160px | |
mega2 |
192px | |
mega3 |
224px | |
giga1 |
256px | |
giga2 |
288px | |
giga3 |
320px | |
tera1 |
384px | |
tera2 |
480px | |
tera3 |
520px |
Aspect ratio
| Token | Value | Demo |
|---|---|---|
ar-square |
1 | |
ar-landscape |
4/3 | |
ar-portrait |
3/4 | |
ar-widescreen |
16/9 | |
ar-golden |
1.618/1 |
Typography
Font stack
There are 3 font stacks set up by default for the font-family CSS property.
| Token | Value |
|---|---|
text |
ui-sans-serif, system-ui, sans-serif |
display |
Avenir, Montserrat, Corbel, URW Gothic, source-sans-pro, ui-sans-serif, sans-serif |
mono |
Dank Mono, Inconsolata, Fira Mono, SF Mono, Monaco, Droid Sans Mono, Source Code Pro, Cascadia Code, Menlo, Consolas, DejaVu Sans Mono, ui-monospace, monospace |
These stacks are optimized for fonts available on device, to maximize for speed and alleviate any layout shifts or flashes. You can find more stacks at Modern Font Stacks.
If you’d like to bring in your own fonts or Google fonts, you can override the display and text tokens inside your theme file.
Font size
Check out typescale.com if you need help creating your own sizes.
| Token | Value | Demo |
|---|---|---|
text-xs |
0.694rem | Sample demo text |
text-sm |
0.833rem | Sample demo text |
text-md |
1rem | Sample demo text |
text-lg |
1.2rem | Sample demo text |
text-xl |
1.44rem | Sample demo text |
display-sm |
1.728rem | Sample demo text |
display-md |
2.074rem | Sample demo text |
display-lg |
2.488rem | Sample demo text |
display-xl |
2.986rem | Sample demo text |
display-mega |
3.583rem | Demo text |
display-giga |
4.299rem | Demo text |
The heading font sizes (--heading-font-size-h1…-h6) build on this scale but are UI tokens; they’re documented with the headings themselves.
Font weight
| Token | Value | Demo |
|---|---|---|
extra-light |
200 | Sample demo text |
light |
300 | Sample demo text |
book |
400 | Sample demo text |
semi-bold |
600 | Sample demo text |
bold |
700 | Sample demo text |
black |
900 | Sample demo text |
Letter spacing
| Token | Value | Demo |
|---|---|---|
tracking-sm |
-0.05em | Sample demo text |
tracking-md |
0.025em | Sample demo text |
tracking-lg |
0.05em | Sample demo text |
tracking-xl |
0.075em | Sample demo text |
tracking-xxl |
0.15em | Sample demo text |
Line height
| Token | Value | Demo |
|---|---|---|
leading-xs |
1 | Sample demo text |
leading-sm |
1.15 | Sample demo text |
leading-md |
1.375 | Sample demo text |
leading-lg |
1.5 | Sample demo text |
leading-xl |
1.75 | Sample demo text |
leading-xxl |
2 | Sample demo text |
Borders
Border radius
| Token | Value | Demo |
|---|---|---|
radius-sm |
3px | |
radius-md |
5px | |
radius-lg |
8px | |
radius-xl |
12px | |
radius-xxl |
16px | |
radius-round |
1e5px |
Border width
| Token | Value | Demo |
|---|---|---|
border-sm |
1px | |
border-md |
2px | |
border-lg |
4px | |
border-xl |
8px | |
border-xxl |
12px |
Drop Shadow
It wouldn’t be super useful to list the values here. You can look at them on Github if you’re curious.
| Token | Demo |
|---|---|
shadow-sm |
|
shadow-md |
|
shadow-lg |
|
shadow-xl |
|
shadow-xxl |
Opacity
| Token | Value | Demo |
|---|---|---|
o-0 |
0 | Opacity level 0 |
o-1 |
0.2 | Opacity level 1 |
o-2 |
0.4 | Opacity level 2 |
o-3 |
0.6 | Opacity level 3 |
o-4 |
0.8 | Opacity level 4 |
o-5 |
1 | Opacity level 5 |
Z-index
| Token | Value |
|---|---|
z-bottom |
-1000000000 |
z-0 |
0 |
z-1 |
10 |
z-2 |
20 |
z-3 |
30 |
z-4 |
40 |
z-5 |
50 |
z-top |
1000000000 |
Transition
| Token | Value |
|---|---|
transition |
220ms ease-in-out |
transition-fast |
100ms ease-in-out |