Linaria is a library which allows you to write CSS inside your JavaScript without the runtime cost. The CSS is extracted out to plain old CSS files with the Babel preset, and critical CSS can be determined with the included helpers.

The idea for Linaria came from css-literal-loader and the syntax of styled-components. It also uses the same parser as styled-components. Glam by Sunil Pai has been another great source of inspiration.

The API looks like this:

1 2 3 4 5 6 7 8 import { css } from 'linaria' ; const title = css ` text - transform : uppercase ; font - weight : 300 ; & : before { border - left : 2px solid grey ; } ` ;

You write CSS syntax (plus nesting) in a tagged template literal and tag it with the css function from Linaria. It returns a class name for you to use. This gets optimized with the Babel preset which reduces it down to just a class name:

1 < strong > const < / strong > title = 'title_gdr45ky' ;

It’s possible to use JavaScript expressions inside the template literal and they will be evaluated at build time, useful for shared utility functions and constants:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 import { css } from 'linaria' ; import { darken } from 'color' ; import colors from './colors' ; import media from './media' ; const AVATAR_SIZE = 48 ; const avatar = css ` background - color : $ { darken ( colors . placeholder , 10 ) } ; height : $ { AVATAR_SIZE } px ; width : $ { AVATAR_SIZE } px ; border - radius : $ { AVATAR_SIZE / 2 } px ; $ { media ( 'large' ) } { border - radius : 2px ; } ` ;

You can also compose multiple styles together with the include helper:

1 2 3 4 5 6 7 8 import { css , include } from 'linaria' ; const heading = css ` font - family : Helvetica , sans - serif ; ` ; const title = css ` $ { include ( heading ) } ; font - weight : 300 ; ` ;

…which is equivalent to writing:

1 2 3 4 5 6 import { css } from 'linaria' ; const title = css ` font - family : Helvetica , sans - serif ; font - weight : 300 ; ` ; < strong > c < / strong >

Features

CSS is extracted at build time, no runtime is included

JavaScript expressions such as function calls, variables, conditionals etc. are supported and evaluated at build time

CSS can be extracted for inlining during SSR

CSS syntax with Sass like nesting

Integrates with existing tools like Webpack to provide features such as Hot Reload

Why?

Existing CSS in JS libraries are pretty amazing as they provide several benefits over the traditional way of writing CSS, making it much more maintainable. They also come with its costs:

CSS needs to be parsed, auto-prefixed and applied to the document at runtime

Bundle-size is increased as the CSS parser needs to be bundled with JavaScript bundle

as the CSS parser needs to be bundled with JavaScript bundle CSS code is bundled with JavaScript , making it impossible to download and parse both in parallel

, making it impossible to download and parse both in parallel Even if you do SSR and serve CSS in parallel, the same CSS is still duplicated in the JavaScript bundled, and wastefully parsed again

These costs may not be significant for all applications, and most of the time, it outweighs the benefits gained from CSS in JS.

The main goal of Linaria is to provide a similar level of flexibility and maintainability while not having the runtime cost associated with it.

What’s the difference from CSS modules?

It’s pretty similar, except a few key differences:

You can write CSS in the same file as rest of the component, no back n forth between files

You can share configuration between your CSS and JavaScript without having to keep multiple files in sync

You can just use JavaScript for loops, conditionals etc., along with various JavaScript libraries like polished

You can make sure that you don’t have any CSS you don’t use with linters like ESLint, and it also works with tools likes Flow or Jest

What’s the difference from other CSS in JS libraries

Despite the similarities, there are many differences from the existing CSS in JS libraries:

The CSS is extracted out from the JavaScript completely, and no runtime is left

It is required that all the CSS can be evaluated at build time, which means it’s currently not possible to use dynamic values like props

The CSS can be served as a separate file, improving load time by parallelizing the downloads and decreasing parsing time

If you are wondering what’s the difference from Emotion, see here.

Want to give it a try? Check it out at https://github.com/callstack-io/linaria/. Don’t forget to star it!

We’re still actively working on it, so please report any issues you find. Pull requests are always welcome.