Type-safe CSS custom properties (CSS variables) for theming purpose
First create your theme object, you can group theme variables by its function (color, spacing, etc). Think of it as design token
import { createTheme } from 'theme-in-css';
export const Theme = createTheme({
color: {
lightPrimary: '#fff',
darkPrimary: '#000',
},
spacing: {
xs: 2,
s: 4,
m: 8,
l: 16,
xl: 32,
},
typography: {
family: {
serif: 'Times New Roman',
sans: 'Calibri',
mono: 'Menlo',
},
}
});
// If you hate typing you can also use a shorter property name
// const t = createTheme({ c: { l1: '#fff', d1: '#000' } });
You can use any any UI libraries/framework that can define style in JS/TS, for example React and Lit.
// React
import React from 'react';
import { Theme } from './theme';
export default function Component() {
// use css prop via emotion/styled-components
// of course inline style works as well
return (
<div
css={{
backgroundColor: Theme.color.darkPrimary,
color: Theme.color.lightPrimary,
margin: Theme.spacing.m,
fontFamily: Theme.typography.family.serif,
}}
>
<h1>It works</h1>
</div>
);
}
// Lit
// You need to wrap Theme inside `unsafeCSS`
import { LitElement, html, css, unsafeCSS as cv } from 'lit';
import { Theme } from './theme';
export default class Component extends LitElement {
static styles = css`
div {
background-color: ${cv(Theme.color.darkPrimary)};
color: ${cv(Theme.color.lightPrimary)};
margin: ${cv(Theme.spacing.m)};
font-family: ${cv(Theme.typography.family.serif)};
}
`;
render() {
return html`
<div>
<h1>It works</h1>
</div>
`;
}
}
If you only create theme and use them in your app, you’ll notice that your app now uses CSS variables to reference a value, but it doesn’t work properly yet because you need to add the CSS into your stylesheet.
string
theme-in-css
provides .css.string
property to dump all theme values as CSS properties. You can create 2 themes light and dark and output them in different style declaration, like this:
import { Theme, DarkTheme } from './theme';
const html = `
<!doctype head>
<html>
<head>
<style>
:root {
${Theme.css.string}
}
@media (prefers-color-scheme: dark) {
${DarkTheme.css.string}
}
</style>
</head>
<body>
</body>
</html>
`;
You can open example to see it in action.
Array<[key: string, value: string]>
You can also use .css.properties
if you want to update the CSS custom property manually using JS.
const root = document.documentElement;
theme.css.properties.forEach(([key, value]) => {
root.style.setProperty(key, value);
});
If you prefer Record<string, string>
instead, you can use Object.fromEntries
const obj = Object.fromEntries(theme.css.properties);
MIT