Theming
Theemo generates a CSS theme file for you supporting color schemes in an adaptive way. Pick color scheme automatically (let the browser decide) or manually? - Choice is yours. You can configure the generation step to whatever you prefer.
Theemo will take care of generating a CSS file and enhance it with classes or CSS media queries as pleased.
Note
Generating themes currently works with light and dark color-schemes, which is only one of the constraints available for tokens. That is this works with the output of style dictionary sync.
This is in heavy need of refactoring to support more constraints, please keep in mind.
Setup
To get you started, install these packages:
pnpm add -D @theemo/cli @theemo/build
Create a config file theemo.config.mjs
, and start with this template. You'll find further configuration in the respective readers and writers that you use.
import { defineConfig } from '@theemo/cli';
export default defineConfig({
build: {...}
});
To run it, place it as a script
in your package.json
and add your theme metadata:
{
"keywords": [
"theemo-theme"
],
"theemo": {
"name": "theemo",
"colorSchemes": [
"light",
"dark"
],
"file": "dist/theemo.css"
},
"scripts": {
"build": "theemo build"
}
}
Now you can run it with:
pnpm build
Configuration
The config options are placed in your config file, within build
property.
auto: boolean
Linking the stylesheet of your theme with:
<link href="path/to/your/theme.css" rel="stylesheet" />
Do you want it to have immediate (autmatically) effect on loading? Or do you want to activate it manually by adding a CSS class to the area where it should have an affect?
base?: string
Default: base.css
The base
file, e.g. the CSS file that does not contain any color scheme related statements.
input: string
and output: string
Default output
: dist
The input
and output
folder. Theemo will take multiple CSS files from an input folder and turns them into one file into the output folder. Theemo expects input files to look like this:
:root {
--foo: bar;
/* ... */
}
colorSchemes: object
If your theme ships with multiple color schemes, this is the way to configure them. Let's start with a sample configuration:
{
"colorSchemes": {
"light": {
"auto": true,
"manual": true
},
"dark": {
"file": "lights-out.css",
"auto": false
}
}
}
The name of the color scheme is the key of the object in which they are defined.
The activation
can happen automatically (if the name is recognized as light
or dark
) which will generate CSS media queries (e.g. @media (prefers-color-scheme: light)
). If a browser is configured to instruct a website to prefer a named color scheme, this will be picked up.
When a file
is given then this will be the input, anyway if defaults to ${name}.css
inside input
folder.
A manual
activation can requested (ie. if activation is auto
) to generate CSS classes to manually enable the color scheme in the preferred area of your website.
defaultColorScheme: string
Given you have multiple color schemes, its good practice to pick one which is used as default. The value here refers to the keys you configured in colorSchemes
.
Examples
Here are some sample configurations and how to use the generated output.
Given for the example:
- There is a
light
anddark
color scheme - The theme is named
ocean
Auto-Theme with light
auto Color Scheme
Config:
import { defineConfig } from '@theemo/cli';
export default defineConfig({
build: {
auto: true,
defaultColorScheme: 'light',
colorSchemes: {
light: {
auto: true,
manual: false
},
dark: {
auto: true,
manual: false
}
}
}
});
Output:
/* No color scheme related tokens */
:root,
.ocean {
--bar: baz;
}
@media (prefers-color-scheme: no-preference), (prefers-color-scheme: light) {
:root,
.ocean {
--foo: lightblue;
}
}
@media (prefers-color-scheme: dark) {
:root,
.ocean {
--foo: darkblue;
}
}
Usage:
<head>
<link rel="stylesheet" href="path/to/ocean.css" type="text/css" />
</head>
<body></body>
Auto-Theme with light
auto Color Scheme and Manual Activation
Config:
import { defineConfig } from '@theemo/cli';
export default defineConfig({
build: {
auto: true,
defaultColorScheme: 'light',
colorSchemes: {
light: {
auto: true,
manual: true
},
dark: {
auto: true,
manual: true
}
}
}
});
Output:
/* No color scheme related tokens */
:root,
.ocean {
--bar: baz;
}
@media (prefers-color-scheme: no-preference), (prefers-color-scheme: light) {
:root,
.ocean {
--foo: lightblue;
}
}
.ocean-light {
--foo: lightblue;
}
@media (prefers-color-scheme: dark) {
:root,
.ocean {
--foo: darkblue;
}
}
.ocean-dark {
--foo: darkblue;
}
Usage:
<head>
<link rel="stylesheet" href="path/to/ocean.css" type="text/css" />
</head>
<body>
<div>Here is the light</div>
<div class="ocean-dark">Lights out</div>
</body>
Manual-Theme with light
auto Color Scheme
Config:
import { defineConfig } from '@theemo/cli';
export default defineConfig({
build: {
auto: false,
defaultColorScheme: 'light',
colorSchemes: {
light: {
auto: true,
manual: false
},
dark: {
auto: true,
manual: false
}
}
}
});
Output:
/* No color scheme related tokens */
.ocean {
--bar: baz;
}
@media (prefers-color-scheme: no-preference), (prefers-color-scheme: light) {
.ocean {
--foo: lightblue;
}
}
@media (prefers-color-scheme: dark) {
.ocean {
--foo: darkblue;
}
}
Usage 1:
<head>
<link rel="stylesheet" href="path/to/ocean.css" type="text/css" />
</head>
<body class="ocean">
Activation for the whole document
</body>
Usage 2:
<head>
<link rel="stylesheet" href="path/to/ocean.css" type="text/css" />
</head>
<body>
Here is no theme active
<div class="ocean">Swim in the water</div>
</body>
Integration
The output from generate
is one CSS file ready to include in your application as demonstrated above. You can publish your theme package (on npm or your internal registry) and include the dist/<your-theme-name>.css
file.
Additionally, when running theemo generate
, this will update your package.json
with a "theemo"
section. With that it is possible to write framework integrations, that will pick up these information and integrate the theme in your framework with zero-config.
Head over to frameworks to see what options are available.