SECRET OF CSS

7 Ways to Inherit Styles Using Styled Components | by Jennifer Fu | Jun, 2022


An in-depth look at styled-components coding techniques

npm trends for styled-components
Image by author

styled-components is a popular library to style React applications, with over four million weekly downloads. It adopts the CSS-in-JS approach, which bundles each JavaScript component with all its belonging CSS rules and dependencies. Combined with code splitting, it only loads the least amount of code necessary.

In styled-components, CSS styles are written as custom React components. It is easy to track which components are unused or undefined during compilation. It improves code manageability, comparing class names or other ways. Since it is CSS in JavaScript, it enables dynamic styling with programming capability.

In a previous article, we have introduced what styled-components is and how to use it. We have been using styled-components for a number of years, and often, we create components extending from the existing components. In this article, we are going to explore how to inherit/share styles using styled components.

We use Create React App as a base to explore styled-components. The following command creates a React project:

% npx create-react-app react-styled-components
% cd react-styled-components

Set up styled-components:

npm i styled-components

styled-components becomes part of dependencies in package.json:

We modify src/App.js to use styled-components.

  • At line 1, styled is imported from styled-components. styled is the default export, used to create the styled.tagname helper method to transform the styling from JavaScript to the actual CSS rules.
  • At lines 3–8, the styled component, Container, extends the styles of div. It contains CSS properties of the flex layout.
  • At lines 10–23, the styled component, BlueItem, extends the styles of div. It contains CSS properties of the blue component.
  • At lines 25–38, the styled component,GreenItem, extends the styles of div. It contains CSS properties of the green component.
  • At lines 40–53, the styled component,OvalItem, extends the styles of div. It contains CSS properties of the oval component.
  • These styled components are used to build a React app at lines 57–61.
  • Execute npm start, and we see the following UI in the browser.
A blue item, a green item, and a oval item — with proper styling
Image by author

The code works. However, there are a number of duplicated properties among BlueItem, GreenItem, and OvalItem.

We should try to inherit/share similar styles.

Some CSS properties can be inherited by child elements, by default, or by setting the value to inherit. This CSS property list shows the following properties are inherited by default: azimuth, border-collapse, border-spacing, caption-side, color, cursor, direction, elevation, empty-cells, font-family, font-size, font-style, font-variant, font-weight, font, letter-spacing, line-height, list-style-image, list-style-position, list-style-type, list-style, orphans, pitch-range, pitch, quotes, richness, speak-header, speak-numeral, speak-punctuation, speak, speech-rate, stress, text-align, text-indent, text-transform, visibility, voice-family, volume, white-space, widows, and word-spacing.

Among our duplicated properties, the font property is inherited by default. It can be moved up to the parent, Container, to save a few lines (line 6 in the code below):

Execute npm start, and it works.

Now, we modify these items to extend from button, instead of div (lines 1, 15, and 29 in code below):

Execute npm start. The font property is no longer inherited.

A blue item, a green item, and a oval item — without font styling
Image by author

It is because most form elements, such as, button, input, textarea, and select, do not inherit the font* properties by default.

Luckily, there is the as prop that can render a styled component as if it is the specified element. It will work properly if we specify button as div in the code below on lines 56, 57, and 58:

Without the as prop, we have to explicitly set the font property to inherit.

The following code works too, with the font property set to inherit at lines 12, 23, and 34. Also, for a button, there is no need to specify these properties: display, align-items, justify-content, and box-sizing.

There is a helper function, createGlobalStyle, which can create shared styles at the topmost level for the whole app.

Here is src/App.js:

  • At line 1, createGlobalStyle is imported, along with styled.
  • At lines 52–54, GlobalStyle is generated with the helper function, createGlobalStyle. Globally, font is set to 20px Arial.
  • At line 58, GlobalStyle is set for the app.
  • Execute npm start, and it works.

If we change items to extend from button, all the problems and solutions are the same as configuring shared styles at the parent level. The only difference is that global is the topmost parent for the whole app.

For our example, three items differ slightly from each other. We can extend the new one from the existing one, and only specify changes.

Here is src/App.js:

  • At lines 21–25, the styled component, GreenItem, extends BlueItem with additional properties.
  • At lines 27–29, the styled component, OvalItem, extends GreenItem with an additional property.
  • Execute npm start, and it works.

For better design, we should have defined a BaseItem, which contains common styles only. Then, BlueItem, GreenItem, and OvalItem extend from BaseItem.

We did not do it “the proper way” for two reasons:

  1. Show that the sub-styled components can overwrite the base styles.
  2. Save some lines of code with fewer components.

Instead of extending styled components, we can compose css props to achieve the same styles. There is a helper function, css, which generates CSS properties from a template literal with interpolations.

Here is src/App.js:

  • At line 1, css is imported, along with styled.
  • At lines 10–19, the css template literal, blueItem, generates CSS properties that is used at line 34.
  • At lines 21–25, the css template literal, greenItem, generates additional CSS properties. blueItem and greenItem are composed and used at line 35.
  • At lines 27–29, the css template literal, ovalItem, generates the additional CSS property. blueItem, greenItem, and ovalItem are composed and used at line 36.
  • Execute npm start, and it does not work properly.
A blue item, a green item, and a oval item — without styling
Image by author

What happened?

The css prop is not button’s attribute. In order to make it work, babel-plugin-styled-components need to be used to turn any element with css into a styled component.

After styled-components is installed, babel-plugin-styled-components and and babel-plugin-macros come with it in package-lock.json.

All we need to do is to import items from the macro directory:

import styled, { css, keyframes } from 'styled-components/macro';

Want to try another solution with babel-plugin-styled-components?

Execute npm run eject, and add Babel plugin (line 5 in code below) to the ejected package.json.

Either way, it works as expected.

A blue item, a green item, and a oval item — with proper styling
Image by author

Alternatively, the compositions can be done in the template literals (lines 22 and 29 in code below):

We can pass a function to interpolate the styled component’s template literal and use it to compute the style value.

There are multiple ways to define interpolate props. Here is an example that sets props to fontStyle, color, and borderRadius:

  • At lines 10–19, the styled component, Item, takes the props, fontStyle, color, and borderRadius. font-style (line 14), color (line 15), border (line 17), and border-radius (line 18) adapt the values based on the props.
  • Execute npm start, and it works.

Here is an example that sets props to itemType:

  • At lines 10–21, the styled component, Item, takes the prop, itemType. font-style (lines 14–25), color (line 16), border (lines 18–19), and border-radius (line 20) adapt the values based on itemType.
  • Execute npm start, and it works.

In the above code, we have configured color as follows:

What if we want to make ovalItem to be purple? The multiple ternary operations would make the code hard to read.

The helper function, css, can be used to compute CSS props.

Here is src/App.js:

  • At line 1, css is imported, along with styled.

Instead of using the function to generate each property value, we use it to compute CSS props (lines 17–22, lines 24–29, and lines 31–36).

Execute npm start, and we see the following UI in the browser.

A blue item, a green item, and a oval item — with proper styling
Image by author

Alternatively, the interpolate function can be defined outside using the css helper (lines 10–33 in code below).

styled-components optionally supports writing CSS as JavaScript objects, instead of strings. This makes it easy and useful to manipulate objects.

Here is src/App.js:

  • At lines 10–19, the styled object, blueItemObject, is defined.
  • At line 21, the styled component, BlueItem, is created from blueItemObject.
  • At lines 23–28, the styled object, greenItemObject, is defined by blueItemObject and additional props.
  • At line 30, the styled component, GreenItem, is created from greenItemObject.
  • At lines 32–37, the styled object, ovalItemObject, is defined by greenItemObject and additional props.
  • At line 39, the styled component, OvalItem, is created from ovalItemObject.
  • Execute npm start, and it works properly.

styled-components is a popular library to style React applications. It is widely adopted by React projects. Frequently, it is needed to create components extending from the existing components. We have explored seven ways how to inherit/share styles using styled components.

Thanks for reading.

Hopefully, some ways are useful for your projects.



News Credit

%d bloggers like this: