Skip to main content

Command Palette

Search for a command to run...

5 things you didn't know you can do in CSS-in-JS - LogRocket Blog

Updated
19 min read
5 things you didn't know you can do in CSS-in-JS - LogRocket Blog

[

Advisory boards aren’t only for executives. Join the LogRocket Content Advisory Board today →

](https://lp.logrocket.com/blg/content-advisory-board-signup).metrics-banner {padding: 8px 0px; background: #764abc ;color: #ffffff;} .metrics-banner h6 {color: #ffffff;text-align:center; margin: 0px !important;} #metrics-embed {width: 65.5%; margin: 0px auto; display: block;} .mediumnavigation {padding: 0px 0px 8px 0px;} @media all and (max-width: 800px){ .mediumnavigation{box-shadow: none !important;} #metrics-embed {width: 90%;} .mainheading {padding: 4rem 0 1rem 0;} }

LogRocket blog logo

2021-07-29

1426

#css-in-js#react

Esteban Herrera

48

Jul 29, 2021 ⋅ 5 min read

5 things you didn’t know you can do in CSS-in-JS

Esteban Herrera Family man. Java and JavaScript developer. Swift and VR/AR hobbyist. Like books, movies, and still trying many things. Find me at eherrera.net

LogRocket Galileo logo

Introducing Galileo AI

LogRocket’s Galileo AI watches every session, surfacing impactful user struggle and key behavior patterns.

LEARN MORE

const threshold = 2000; const isMobile = window.matchMedia("(max-width: 1280px)").matches; window.addEventListener('scroll', (event) => { if (isMobile) { return; } const gutter = document.querySelector(".plug-gutter"); // show it if it is hidden and we have scrolled past the threshold if (window.scrollY > threshold && !gutter.classList.contains("show")) { gutter.classList.add("show"); window.toggleToc(true); } // hide it if we scroll back above the threshold if (window.scrollY < threshold && gutter.classList.contains("show")) { gutter.classList.remove("show"); window.toggleToc(false); } });

.plug-dev-top--card { border: 2px solid rgba(118, 74, 188, 0.2); border-radius: 8px; background-color: #491d90; justify-content: space-between; align-items: center; padding: 16px; font-family: 'Proxima Nova', sans-serif; display:flex; gap: 1rem; cursor: pointer; } .plug-dev-top--logo { width: 48px; height: 48px; border-radius: 50%; } .plug-dev-top--blurb { h2 { font-weight: 800; font-size: 22px; line-height: 22px; color: #fff; width: 70%; margin: 0 0 5px 0; } h3 { font-weight: 900; font-size: 13px; line-height: 13px; letter-spacing: 0.1em; color: #fff; opacity: 0.5; white-space: nowrap; margin: 0; } } .plug-dev-top--cta { background-color: #fff; color: #764abc; border: none; border-radius: 4px; padding: 10px; font-size: 16px; font-weight: 800; font-family: 'Proxima Nova', sans-serif; text-decoration: none; width: 25%; text-align: center; &:hover { text-decoration: none; color: #a58ec8; } } .plug-dev-top--asset { position: relative; height: 400px; overflow: hidden; transition: all 0.3s ease; margin-top: 30px; &.lr-hidden { height: 0; margin: 0; } }

See how LogRocket's Galileo AI surfaces the most severe issues for you

No signup required

Check it out

const wistiaIframe = document.querySelector("#galileo-wistia-iframe"); wistiaIframe.addEventListener('load', () => { const player = wistiaIframe.wistiaApi; window.document.querySelector(".plug-dev-top").addEventListener('click', () => { const videoContainer = window.document.querySelector(".plug-dev-top--asset"); videoContainer.classList.toggle('lr-hidden'); if (videoContainer.classList.contains("lr-hidden")) { player.pause(); } else { player.play(); } }); });

Editor’s note: This post was last updated on 29 July 2021 for accuracy and clarity. For more up-to-date information on CSS-in-JS, you can also check out this article on CSS-in-JS libraries.

5 Things You Can Do with CSS-in-JS

#replay-signup { margin-block: 1rem; display: flex; gap: 0.5rem; flex-direction: column; align-items: center; border: 1px solid #E6DFF6; border-radius: 16px; padding: 0.5rem 2rem; background-color: #F4F0FB; font-family: 'Proxima Nova', sans-serif; font-size: 0.95rem; h3 { margin: 0; font-weight: bold; } p { max-inline-size: 65ch; } .replay-signup-form-wrapper { width: 60%; } .nf-before-form-content { display: none; } input.nf-element[type="submit"] { background-color: #764abc; color: #fff; border-radius: 8px; padding-block: 10px; height: unset; width: 100%; display: block; } .nf-response-msg { font-size: 1.2rem; text-align: center; } }

🚀 Sign up for The Replay newsletter

The Replay is a weekly newsletter for dev and engineering leaders.

Delivered once a week, it's your curated guide to the most important conversations around frontend dev, emerging AI tools, and the state of modern software.

Notice: JavaScript is required for this content.

var formDisplay=1;var nfForms=nfForms||[];var form=[];form.id='48';form.settings={"objectType":"Form Setting","editActive":true,"title":"Replay Newsletter Signup","show_title":0,"allow_public_link":0,"embed_form":"","clear_complete":1,"hide_complete":1,"default_label_pos":"above","wrapper_class":"","element_class":"","form_title_heading_level":"3","key":"","add_submit":0,"changeEmailErrorMsg":"Please enter a valid email address!","changeDateErrorMsg":"Please enter a valid date!","confirmFieldErrorMsg":"These fields must match!","fieldNumberNumMinError":"Number Min Error","fieldNumberNumMaxError":"Number Max Error","fieldNumberIncrementBy":"Please increment by ","formErrorsCorrectErrors":"Please correct errors before submitting this form.","validateRequiredField":"This is a required field.","honeypotHoneypotError":"Honeypot Error","fieldsMarkedRequired":"Fields marked with an *<\/span> are required","currency":"","unique_field_error":"A form with this value has already been submitted.","logged_in":false,"not_logged_in_msg":"","sub_limit_msg":"The form has reached its submission limit.","calculations":[],"conditions":[],"mp_breadcrumb":1,"mp_progress_bar":1,"mp_display_titles":0,"formContentData":[{"formContentData":["email","submit_1760469924554"],"order":0,"type":"part","clean":true,"title":"Part Title","key":"hzyqqobd"}],"objectDomain":"display","drawerDisabled":false,"ninjaForms":"Ninja Forms","fieldTextareaRTEInsertLink":"Insert Link","fieldTextareaRTEInsertMedia":"Insert Media","fieldTextareaRTESelectAFile":"Select a file","formHoneypot":"If you are a human seeing this field, please leave it empty.","fileUploadOldCodeFileUploadInProgress":"File Upload in Progress.","fileUploadOldCodeFileUpload":"FILE UPLOAD","currencySymbol":"$","thousands_sep":",","decimal_point":".","siteLocale":"en_US","dateFormat":"m\/d\/Y","startOfWeek":"1","of":"of","previousMonth":"Previous Month","nextMonth":"Next Month","months":["January","February","March","April","May","June","July","August","September","October","November","December"],"monthsShort":["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],"weekdays":["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],"weekdaysShort":["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],"weekdaysMin":["Su","Mo","Tu","We","Th","Fr","Sa"],"recaptchaConsentMissing":"reCaptcha validation couldn't load.","recaptchaMissingCookie":"reCaptcha v3 validation couldn't load the cookie needed to submit the form.","recaptchaConsentEvent":"Accept reCaptcha cookies before sending the form.","currency_symbol":"","beforeForm":"","beforeFields":"","afterFields":"","afterForm":""};form.fields=[{"objectType":"Field","objectDomain":"fields","editActive":false,"order":999,"idAttribute":"id","type":"email","label":"Email","key":"email","label_pos":"hidden","required":1,"default":"","placeholder":"Email","container_class":"","element_class":"","admin_label":"","help_text":"","custom_name_attribute":"email","personally_identifiable":1,"value":"","manual_key":true,"drawerDisabled":false,"id":401,"beforeField":"","afterField":"","parentType":"email","element_templates":["email","input"],"old_classname":"","wrap_template":"wrap"},{"objectType":"Field","objectDomain":"fields","editActive":false,"order":999,"idAttribute":"id","type":"submit","label":"Submit","processing_label":"Submitting...","container_class":"","element_class":"","key":"submit_1760469924554","admin_label":"","drawerDisabled":false,"id":402,"beforeField":"","afterField":"","value":"","label_pos":"above","parentType":"textbox","element_templates":["submit","button","input"],"old_classname":"","wrap_template":"wrap-no-label"}];nfForms.push(form);

{{{ data.renderProgressBar() }}} {{{ data.renderBreadcrumbs() }}} {{{ data.renderPartTitle() }}}

{{{ data.title }}}

{{{ data.renderNextPrevious() }}}
    <# if ( data.showPrevious ) { #>
  • <# } #> <# if ( data.showNext ) { #>
  • <# } #>

function registerNinjaFormsCallback() { if (!(window.nfRadio && window.lr_analytics)) { return; } window.nfRadio.channel("forms").on("submit:response", function(submission) { console.log(submission); if (submission.data.form_id !== "48") { return; } window.lr_analytics.track("blog-replay-newsletter-signup", { post: window.location.pathname, email: submission.data.fields_by_key?.email?.value, }); }); } registerNinjaFormsCallback();

What does CSS-in-JS solve?

In addition to traditional CSS, inline styles and CSS-in-JS can also be used to style React applications.

Even though inline styles enable you to pass a JavaScript object to the style attribute (as seen in the code snippet below), it doesn’t support all CSS features:

import React from "react";

function App() { const myStyle = { fontSize: 24, lineHeight: "1.3em", fontWeight: "bold" };

return (

Hello world

); } export default App;

On the other hand, CSS-in-JS libraries like Aphrodite, styled-components, JSS, Emotion, Radium, etc. give developers the ability to not only style components with JavaScript but also tackle some CSS limitations, such as the lack of dynamic functionality, scoping, and portability when using them:

// Here's an implementation of the inline style code snippet above using Aphrodite

import React from "react"; import { StyleSheet, css } from "aphrodite";

function App() { const styles = StyleSheet.create({ myStyle: { fontSize: 24, lineHeight: "1.3em", fontWeight: "bold" } }); return (

Hello World!
); } export default App;

In this article, I will highlight five things you didn’t know you could do in CSS-in-JS using the CSS-in-JS libraries mentioned above as a case study. 👇

1. CSS-in-JS lets you refer to other styled components

Libraries like styled-components and Emotion allow you to use tagged template literals to create React components from styles:

// Create a component that renders a

element with blue text import React from "react"; import styled from "styled-components";

function App() { const BlueText = styled.p` color: blue; `;

return (

My blue text
); }

export default App;

But they also allow you to target other styled components (like if you were using CSS selectors):

import React from "react"; import styled from "styled-components";

function App() { const ImportantText = styled.div` font-weight: bold; `;

const Text = styled.div` color: gray; ${ImportantText} { font-style: italic; } `;

return (

Text in gray Important text in gray, bold and italic Important text bold
); }

export default App;

This is useful when it is combined with pseudo-classes; for example, to change the color of a component on hover:

import React from "react"; import styled from "styled-components";

function App() { const ImportantText = styled.div` font-weight: bold; `;

const Text = styled.div` color: gray; &:hover ${ImportantText} { color: red; } `;

return (

Text in gray Important text in gray, bold and italic Important text bold
); }

export default App;

2. JSS (or other libraries) can extend the features of some libraries

Let’s say you’ve used Aphrodite to style your application and now you need to support themes.

The problem is that Aphrodite doesn’t support theming easily. At least, not as easy as Emotion does.

However, there are two projects that bridge the core of JSS with Aphrodite and styled-components: aphrodite-jss and styled-jss.

This way, you can keep the good parts of Aphrodite (or styled-components) and use all the features and plugins of JSS, from rule caching to rule isolation, and for themes, the theming package, which provides the following high-order components:

  • ThemeProvider, which passes a theme object down the React tree by context
  • withTheme, which allows you to receive a theme object and it updates as a property

For example:

import React from "react"; import { createUseStyles, ThemeProvider, useTheme } from "react-jss";

function App() { const useStyles = createUseStyles({ wrapper: { padding: 40, background: ({ theme }) => theme.background, textAlign: "left" }, title: { font: { size: 40, weight: 900 }, color: ({ theme }) => theme.color }, link: { color: ({ theme }) => theme.color, "&:hover": { opacity: 0.5 } } });

const Comp = () => { const theme = useTheme(); const classes = useStyles({ theme }); return (

Hello There!

); };

const theme = { background: "blue", color: "white" };

return (

); }

export default App;

In the particular case of Aphrodite and themes, as another example, you can also use react-with-styles, which interfaces with Aphrodite and JSS, among others, to access theme information when defining styles.

3. CSS-in-JS can chain multiple animations with keyframes

Unlike inline styles, CSS-in-JS allows you to define animations using keyframes.

For example, this is how it’s done with styled-components:

import React from "react"; import styled, { keyframes } from "styled-components";

function App() { const MoveAnimation = keyframes` 0% { transform: translate(0, 0); } 50% { transform: translate(50px, 0); } `;

const MyComponent = styled.div` display: inline-block; margin: 50px; width: 200; position: relative; animation: ${MoveAnimation} 1.5s ease infinite; `;

return (

Hello There!
); }

export default App;

But what not many people know is that you can chain multiple animations by using more than one keyframe object in the animation property.

Here’s the above example modified to combine two animations:

import React from "react"; import styled, { css, keyframes } from "styled-components";

function App() { const MoveAnimation = keyframes` 0% { transform: translate(0, 0); } 50% { transform: translate(50px, 0); } `;

const ColorAnimation = keyframes` from {color: red;} to {color: blue;} `;

const MyComponent = styled.div` display: inline-block; margin: 50px; width: 200; position: relative; animation: ${(props) => css` ${MoveAnimation} 1.5s ease infinite, ${ColorAnimation} 1.5s linear infinite `}; `;

return (

Hello There!
); }

export default App;

4. You can declare global styles with CSS-in-JS

Everything in CSS is global, and one of the purposes of using CSS-in-JS is to eliminate global style definitions.

However, there may be valid uses of global styles; for example, when you want to apply the same font styles to every element in your page.

Of course, you can always use traditional CSS, importing it via Webpack or declaring it in the index.html file.

But if you’re serious about using JavaScript for all your styles, some libraries actually allow you to define global styles via helper components or extensions/plugins.


[

Over 200k developers use LogRocket to create better digital experiences

Learn more →

](https://lp.logrocket.com/blg/learn-more)


@media all and (max-width: 800px){ .tweet-embed-container {flex-direction: column !important;} .single-tweet, .embed-tweet-right {width: 100% !important;} } .embed-link {text-decoration: none;} .embed-link:hover {text-decoration: none;} .tweet-embed-container {border-radius: 20px; background: radial-gradient(79.69% 102.24% at 100% 100.11%, rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0)), radial-gradient(89.7% 115.09% at 3.43% 2.75%, rgba(255, 255, 255, 0.7), rgba(255, 255, 255, 0)), #764ABC; background-blend-mode: overlay, overlay, normal; box-shadow: 0 4px 0 #d5d5d5; width: auto; padding: 20px 15px; display: flex; flex-direction: row; justify-content: space-evenly; align-items: center; margin: 0 auto; gap: 3%; } .single-tweet {width: 50%;} .single-tweet img {max-width: 100%;height: auto; border-radius:7px;} .embed-tweet-right {width: 46%;} .embed-tweet-right h2 {font-family: 'Avenir'; font-style: normal; font-weight: 500; font-size: 16px; line-height: 28px; color: #FFFFFF;} .embed-btn { display: flex; flex-direction: row; justify-content: left; width: 170px; gap: 5px; align-items: center; padding: 0px 10px; font-family: 'Avenir'; font-style: normal; font-weight: 900; font-size: 16px; line-height: 16px; color: #764ABC; height: 48px; /* White */ background: #FFFFFF; mix-blend-mode: normal; box-shadow: 0px 24px 30px rgba(0, 0, 0, 0.11); border-radius: 80px; border: none; }

In Radium, you can use the Style component to render a styled element with global styles.

For example:

More from this blog

Binarydiods

272 posts

5 things you didn't know you can do in CSS-in-JS - LogRocket Blog