const { classes } = css({
button : {
backgroundColor : 'blue',
color : 'white',
padding : '10px',
borderRadius : '5px'
}
});
const Button = () => <button className={classes.button}>Click me</button>;
Styles are generated when the module is initialized, rather than during component rendering. This eliminates runtime style generation, improving performance and reducing complexity.
CSSFUN scopes styles to the component, preventing style leakage and promoting modularity. It keeps both logic and styling in the same file for easier management.
CSSFUN is compatible with any environment. At just 1.7KB, it adds minimal overhead to your projects.
CSSFUN can be used directly in the browser, eliminating the need for complex build tools or configurations.
CSSFUN supports server-side rendering out of the box, optimizing initial load times without duplicating styles.
With built-in theme support, CSSFUN uses CSS variables to manage light and dark color schemes. Themes update automatically based on user preferences, no re-renders needed.
$ npm install cssfun
import { css } from 'cssfun';
import { css } from 'https://esm.run/cssfun';
<script>
tag<script src="https://cdn.jsdelivr.net/npm/cssfun"></script>
const { css } = CSSFUN;
const { classes } = css({
button : {
backgroundColor : 'blue',
color : 'white',
padding : '10px',
borderRadius : '5px'
}
});
const Button = () => <button className={classes.button}>Click me</button>;
Renderers are functions that transform style objects into CSS strings.
These are the built-in renderers transformations:
css({
root : {
backgroundColor : 'black'
}
}).toString();
<style data-fun-uid="fun-uwitok">
.fun-uwitok-root {
background-color: black;
}
</style>
Use &
to reference the selector of the parent rule
css({
button : {
backgroundColor : 'white',
'&:hover' : {
backgroundColor : 'black'
},
'& span' : {
color : 'blue'
}
}
}).toString();
<style data-fun-uid="fun-1pxyvx7">
.fun-1pxyvx7-button {
background-color: white;
}
.fun-1pxyvx7-button:hover {
background-color: black;
}
.fun-1pxyvx7-button span {
color: blue;
}
</style>
Deep nesting
css({
button : {
backgroundColor : 'white',
'&:active' : {
backgroundColor : 'black',
'&:hover' : {
backgroundColor : 'blue'
}
}
}
}).toString();
<style data-fun-uid="fun-169vukw">
.fun-169vukw-button {
background-color: white;
}
.fun-169vukw-button:active {
background-color: black;
}
.fun-169vukw-button:active:hover {
background-color: blue;
}
</style>
Use $
to reference a local class within the same StyleSheet
instance
css({
button : {
backgroundColor : 'white'
},
'$button:hover' : {
backgroundColor : 'black'
},
'$button span' : {
color : 'blue'
}
}).toString();
<style data-fun-uid="fun-2xfpy0">
.fun-2xfpy0-button {
background-color: white;
}
.fun-2xfpy0-button:hover {
background-color: black;
}
.fun-2xfpy0-button span {
color: blue;
}
</style>
Global block
css({
'@global' : {
body : {
backgroundColor : 'black'
}
}
}).toString();
<style data-fun-uid="fun-ml03n3">
body {
background-color: black;
}
</style>
Nested global block
css({
root : {
'@global' : {
a : {
color : 'black'
}
}
}
}).toString();
<style data-fun-uid="fun-1eia2eq">
.fun-1eia2eq-root a {
color: black;
}
</style>
Global prefix
css({
'@global body' : {
backgroundColor : 'black'
}
}).toString();
<style data-fun-uid="fun-1p1av20">
body {
background-color: black;
}
</style>
Nested global prefix
css({
root : {
'@global a' : {
color : 'black'
}
}
}).toString();
<style data-fun-uid="fun-xvd6jj">
.fun-xvd6jj-root a {
color: black;
}
</style>
When composed, the first renderer receives the styles object, and the final one outputs the resulting CSS string.
You can customize the renderers by setting the renderers
array on the StyleSheet
instance.
If passed via options.renderers
, they will be automatically added to the instance.
Elements in the renderers
array can be either functions or strings that reference methods of the StyleSheet
instance. These
methods will be bound to the instance before they are invoked.
By default, StyleSheet
are rendered using the built-in renderers: [this.renderStyles, this.parseStyles]
.
A theme is a StyleSheet
that provides access to CSS variables
for consistent styling across your application. It supports multiple color schemes,
including light
, dark
, light dark
(default, adapts to system preferences), and normal
.
Themes allow your components to automatically adapt to changes in the user's system preferences
or use a fixed color scheme.
The createTheme
function generates a theme StyleSheet instance.
It accepts a themes
object, which defines variables for the specified color schemes, and an
options
object to customize the theme generation.
Each key in the themes
object corresponds to a color scheme (light
, dark
, normal
),
and its value is an object of key-value pairs that will be converted into CSS variables.
Define styles for light
and dark
color schemes using the createTheme
function.
const theme = createTheme({
light : {
colorPrimary : 'black',
backgroundLevel1 : 'white'
},
dark : {
colorPrimary : 'white',
backgroundLevel1 : 'black'
}
});
The options.colorScheme
parameter specifies which color scheme(s) to use. Possible values are:
light
: Uses the light
theme only.dark
: Uses the dark
theme only.light dark
(default): Supports both light
and dark
themes, adapting to system preferences. You can override the system preference by setting the data-color-scheme
attribute to light
or dark
on a parent element.normal
: Uses the normal
theme only.The options.cssVarsPrefix
parameter allows you to customize the prefix for the generated CSS variables.
By default, the prefix is fun
. For example, a key colorPrimary
in the theme will generate a CSS variable
like --fun-colorPrimary
.
The generated theme includes a root
class, which exposes all the theme's CSS variables to any element
that uses this class and its descendants. You can apply this class to the body
element to style the
entire application, or to the root element of a specific component to apply the theme to just part of your UI.
// Add theme class to the body
document.body.classList.add(theme.classes.root);
The themes
object is automatically converted into CSS variables. For example:
{ backgroundLevel1 : 'black' }
is converted into the CSS variable --fun-backgroundLevel1
.
Nested structures like:
{
palette : {
common : {
black : '#000'
}
}
}
are converted into --fun-palette-common-black
.
You can use these variables in your component styles, even before the theme is applied. Your components will automatically update when the theme or system color scheme changes.
const { classes } = css({
button : {
color : 'var(--fun-colorPrimary)',
backgroundColor : 'var(--fun-backgroundLevel1)'
},
});
const Button = ({ label }) => <button className={classes.button}>{label}</button>;
Easily add your styles to the server-rendered HTML by embedding the StyleSheets as a
string within the <head>
of your page.
// Creating a theme
const theme = createTheme(themes);
// Express route that renders the app and returns HTML to the browser
app.get('*', (req, res) => {
// Render the app as an HTML string
const html = renderToString(<App />);
// Get all StyleSheets styles as a string of <style> elements
const styles = StyleSheet.toString();
// Get the root class name from the theme
const cls = theme.classes.root;
// Create the full HTML page template
const template = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Waving Cat</title>
${styles}
</head>
<body class="${cls}">
<div id="root">${html}</div>
<script src="/bundle.js"></script>
</body>
</html>
`;
// Send the complete HTML response
res.send(template);
});
When the app is hydrated on the client side, the styles are preserved and wonβt be recreated.
Complete API documentation can be found here.
The examples
folder contains various sample projects demonstrating how to use CSSFUN in
different environments and frameworks. Each example is a standalone project that you can run locally
to see CSSFUN in action.