CSS in JavaScript Using Emotion
CSS in JavaScript Using Emotion
×
Join the Community!
Get expert insights straight to your inbox. Subscribe
below to receive computing updates!
Emotion is a library for CSS-in-JS, an approach where you make style specifications in
JavaScript code.
There are quite a few libraries you can draw on. Probably the best known in this area are
Styled Components and Emotion. Styled Components specializes in React, while Emotion
takes a framework-independent approach. In the next sections, we'll introduce Emotion as a
possible solution because it provides the same syntax as Styled Components, but more
features, and you can use the library very well with React.
You can use Emotion either with the css prop or with the styled approach. The css prop
allows you to write the styles in a prop and apply them directly in the element. This variant is
similar to direct styling via the style prop. The styled approach uses a kind of higher-order
component. This exploits a rarely used part of the ECMAScript standard by using the tag
function of the template strings, a function executed to process the template string.
By default, the JavaScript environment provides a standard tag function that is used to
perform variable substitution. Emotion, or which follows the same principles as the idea
generator styled components, takes this idea further and allows you to create components
with local style specifications via template strings. In addition to just styling components, the
Styled Components library offers numerous other useful features, some of which we’ll take a
closer look at ahead and integrate into an example application.
Installing Emotion
Emotion is an open-source library developed under the MIT license on GitHub. Depending
on which variant of Emotion you want to use, you need to install different packages. For use
in the css prop, all you need is the @emotion/react package, which you can install using
npm install @emotion/react. If you want to use the styled approach, you have to install the
@emotion/styled package in addition to that; that is, you need to run the npm install
@emotion/react @emotion/styled command. Both packages come with their own type
definitions, so you don't need to install additional packages to use them with TypeScript.
const headerStyle = {
};
const cellStyle = {
};
return (
<table css=>
<thead css={headerStyle}>
<tr>
<th>Title</th>
<th>Author</th>
<th>ISBN</th>
<th>Rating</th>
</tr>
</thead>
<tbody>
{books.map((book) => {
return (
<tr
key={book.id}
css={css`
&:nth-of-type(2n) {
background-color: #ddd;
`}
>
<td css={cellStyle}>{book.title}</td>
<td css={cellStyle}>{book.author}</td>
<td css={cellStyle}>{book.isbn}</td>
<td css={cellStyle}>
</td>
</tr>
);
})}
</tbody>
</table>
);
};
The entry point to the file consists of two comments that Emotion and the build process
respectively need to handle the css prop correctly. The first comment switches the runtime of
the preset-react plugin to classic mode. The second comment makes sure that the css prop
is processed correctly by Emotion. If your development environment has problems with the
correct processing of the css prop, you can fix it with the line: /// <reference
types="@emotion/react/types/css-prop" />
Before you get into the component, you define two style objects. The headerStyle object is
responsible for the appearance of the table's header row, while cellStyle is responsible for
the appearance of the table's individual cells.
In the BooksList component itself, you can see different variants of using the css prop:
Inline object: In the table element, you define the css prop and set the styling directly
inline. On the one hand, this has the advantage that you can see at a glance which
styles are defined for an element. If you use this approach for multiple elements and
have multiple style specifications per element, the source code of your component
quickly becomes confusing. You should therefore only use this variant sparingly.
External object: For the table header and the individual cells, you swap out the styles
to separate objects so that the style definitions do not appear directly in the component.
Using this variant, you achieve a tidier source code in the component and can reuse
the individual objects in several places, as you can see with the td Also, you can swap
out these style objects to a separate file if needed.
CSS template string: In the third variant, you define a template string with the styles
and provide it with the css function of Emotion. With this approach, you can use
pseudoselectors such as nth-of-type or hover, for example. The same approach applies
to the template string as to an object: you can define it either inline as in the example or
outside the component. Emotion offers a second variant—the styled approach—to style
your components.
The advantage of styled components over the css prop is that you don't need to make any
adjustments to your TypeScript configuration and your component, especially when using
TypeScript. To be able to use styled components, you just need to install the
@emotion/styled package.
There are several approaches to organizing styled components. These range from placing
the components directly in the file where they’re needed to having a separate file per Styled
Component. The first approach has the disadvantage that styled components are relatively
tightly coupled to the component in which they are used. The second approach results in a
very large number of files that may make your application very confusing. A good middle
ground is to group styled components thematically into files.
For the sample application, you create a new file named BooksList.styles.ts. The styled
components of Emotion provide tagging capabilities for all HTML elements, which you can
use to create corresponding elements with style definitions for your application. You can
directly convert the static styles of the table for the table element, the table header, and the
cells. The syntax is similar to the CSS template strings you learned about in the context of
the css prop. This listing shows the implementation of the components as styled
components:
border-collapse: collapse;
`;
`;
`;
To create the styled components, you can use the styled.table, styled.thead, and styled.td
tag functions. You pass the CSS information to them in the template string.
Because styled components are JavaScript strings and not regular CSS, you have no direct
support in your development environment. However, a plugin is available for both WebStorm
and Visual Studio that gives you syntax highlighting and autocompletion for styled
components.
The result of the tag function is a full-fledged React component that you can use within your
application:
return (
<Table>
<THead>
<tr>
<th>Title</th>
<th>Author</th>
<th>ISBN</th>
<th>Rating</th>
</tr>
</THead>
<tbody>
{books.map((book) => {
return (
<tr key={book.id}>
<TD>{book.title}</TD>
<TD>{book.author}</TD>
<TD>{book.isbn}</TD>
<TD>{book.rating && ↩
<span>{'*'.repeat(book.rating)}</span>}</TD>
</tr>
);
})}
</tbody>
</Table>
);
};
As you can see, you can choose the names of your styled components in such a way that,
except for the initial uppercase letter, you won't notice any difference from the React
elements you've been using so far. However, the styled components of Emotion can do
much more for you and your application.
&:nth-of-type(2n) {
background-color: #ddd;
`;
Instead of the nth-child selector, you use the nth-of-type selector in this example. The reason
is that nth-of-type produces the same result as nth-child, but the former is the better variant
for server-side rendering. For this reason, you should generally use this selector. If you use
nth-child, you will receive a corresponding warning in the developer tools console of your
browser advising you against using this selector.
To activate the new component, you need to import it into the BooksList component and
replace the tr element in the body of the table with the TR styled component.
Dynamic Styling
You can also make your styled components dependent on props. This further increases the
flexibility of your components and allows you to support multiple variants. To demonstrate a
styled component that can be controlled by props, you allow your users to highlight an entry
in the table by clicking on a row. The BooksList component then sets the highlight prop for
the respective line, and the TR component takes care of setting the correct background
color.
type TRProps = {
highlight: boolean;
};
&:nth-of-type(2n) {
background-color: #ddd;
highlight &&
css`
&&& {
background-color: yellow;
`}
`;
To support the highlight prop, you first define a type for the component props that contains
the highlight property of Boolean type. Then you can define an arrow function in the template
string of the styled component. By default, this arrow function receives the props you pass to
the component. Depending on whether the highlight prop is set and contains the value true,
you output another template string from the @emotion/react package using the css function.
The &&& selector allows you to ensure that the subsequent background-color specification
is given a higher priority than the nth-oftype selector; otherwise you won’t be able to highlight
the rows colored by it.
Based on this customization you can integrate the new prop into the BooksList component.
The corresponding source code is shown in this listing.
return (
<Table>
<THead>
<tr>
<th>Title</th>
<th>Author</th>
<th>ISBN</th>
<th>Rating</th>
</tr>
</THead>
<tbody>
{books.map((book) => {
return (
<TR
key={book.id}
>
<TD>{book.title}</TD>
<TD>{book.author}</TD>
<TD>{book.isbn}</TD>
<TD>{book.rating && ↩
<span>{'?'.repeat(book.rating)}</span>}
</TD>
</TR>
);
})}
</tbody>
</Table>
);
};
The changes to the BooksList component are limited to the state in which you store the
information about which row is highlighted, and to the TR component itself. Here you define
a click handler that marks the current row as the active row and the highlight prop that
contains the value true or false depending on the currently active row.
`;
`;
In the example, you first define a BaseTd component that you create using styled.td. This
component already contains a basic style with the padding specification. Then you call the
styled function with the BaseTd component, and you can define more styles. This approach
becomes particularly interesting when you use it to implement style inheritance.
As an alternative to the approaches presented so far, you can also include pure CSS
solutions in your React application, such as Tailwind.
Editor’s note: This post has been adapted from a section of the book React: The
Comprehensive Guide by Sebastian Springer.
Recommendation
React
React.js makes developing dynamic user interfaces
faster and easier than ever. Learn how to get the
most out of the library with this comprehensive
guide! Start with the basics: what React is and how
it works. Then follow practical code examples to
build an application, from styling with CSS to
maximizing app performance. Whether you’re new
to JavaScript or you’re an advanced developer,
you’ll find everything you need to build your frontend
with React!
Learn More
by Rheinwerk Computing
Rheinwerk Computing is an imprint of Rheinwerk Publishing and
publishes books by leading experts in the fields of programming,
administration, security, analytics, and more.
Comments
FIRST NAME*
LAST NAME
EMAIL*
WEBSITE
COMMENT*
Privacy - Terms
Submit Comment
How to Make Web Tables Accessible for The Basic Structure of a React Native
Everyone Application
Rheinwerk Computing is an imprint of Rheinwerk Publishing and publishes resources All Topics Web Development HTML & CSS
that will help you accelerate your computing journey. The Rheinwerk Computing Blog
Programming DevOps Security
is designed to provide helpful, actionable information on a variety of topics, including
Languages
programming, administration, security, and analytics! Python What Is?
JavaScript
Software
Java Development