Introduction to Using Styled Components

In the React world, everyone has gotten used to styling their components by passing a className prop to them, referencing the CSS classes defined in some stylesheet. As you know, CSS classes encapsulate the styles needed for pages and page components, centralize them for easier maintenance and use, and are meant to ensure a consistent visual experience throughout a website. That’s great, but now with React, we're more and more thinking in smaller independent and reusable components, distinct from the rest – so why should their styles and classes contribute to bloating a global stylesheet?

Copy
<Button className="btn btn-primary">Primary</Button>

The styled-components approach doesn’t suggest to get rid of CSS classes altogether. But with self-contained React components, they’re just an intermediary layer we can do without.

In this guide, we are going to show you how to benefit the most from using styled components in a Scrivito-based app.

Getting started

First, in your project’s root directory, run the following to install the styled-components module:

Copy
npm install --save styled-components

That’s all – now, don’t forget to import styled from "styled-components"; in your JS files.

Basic usage

Styled-components lets you attach styles to components directly. This way, components encapsulate their styles, obviating the need for CSS classes:

Copy
// Normal Button component
const Button = styled.button`
  color: blue;
  font-size: 1em;
  margin: 1em;
  padding: 0.25em 1em;
  border: 2px solid blue;
  border-radius: 3px;
`;

// DangerButton component based on Button, but with overridden colors
const DangerButton = styled(Button)`
  color: red;
  border-color: red;
`;

// ...
render(
  <div>
    <Button>Normal Button</Button>
    <DangerButton>Danger Button</DangerButton>
  </div>
);

The styled method lets you attach styles to HTML elements (styled.button) or to components (styled(Button)) using a template string.

As you can see, we’ve additionally derived a slightly different version, a DangerButton, from the Button component by overriding two styles. As a more dynamic approach, instead of providing a dedicated DangerButton component, we could have used a prop for switching the ”Button” styles:

Copy
// The Button responding to a prop, danger, to switch styles
const Button = styled.button`
  color: ${props => props.danger ? 'red' : 'blue'};
  font-size: 1em;
  margin: 1em;
  padding: 0.25em 1em;
  border: 2px solid ${props => props.danger ? 'red' : 'blue'};
  border-radius: 3px;
`;

render(
  <div>
    <Button danger>Danger Prop Button</Button>
  </div>
);

Having access to a component’s props inside of style definitions makes this approach so tempting, especially with respect to theming (take a look at the ThemeProvider wrapper component, for example).

Styling Scrivito components

Scrivito includes several helper components for rendering CMS content like widgets, HTML markup, images, and a couple more. If Scrivito’s UI is active, these built-in components make content editable in “Edit” mode. Scrivito.ContentTag, for example, renders an attribute value of a CMS object or widget:

Copy
<Scrivito.ContentTag tag="h1" content={widget} attribute="title" />

If you wish to directly change, for instance, the appearance of a widget, here’s how this can be done using the example of the FactWidget included in the Scrivito Example App. Originally, this widget’s component looks like this:

src/Widgets/FactWidget/FactWidgetComponent.js
Copy
import * as React from "react";
import * as Scrivito from "scrivito";

Scrivito.provideComponent("FactWidget", ({ widget }) => (
  <div className="fact">
    <Scrivito.ContentTag
      content={widget}
      attribute="value"
      className="value"
      tag="span"
    />
    <Scrivito.ContentTag
      content={widget}
      attribute="key"
      className="key"
      tag="span"
    />
  </div>
));

The widget renders the values of two attributes (value and key). We optionally want to add a border to them, so we’re wrapping Scrivito.ContentTag in a styled component, BorderedFact:

src/Widgets/FactWidget/FactWidgetComponent.js
Copy
import * as React from "react";
import * as Scrivito from "scrivito";
import styled from "styled-components";

const BorderedFact = styled(Scrivito.ContentTag)`
  border: 1px solid ${props => props.borderColor || 'transparent'};
  border-radius: 3px;
  margin: 1px;
`;

Scrivito.provideComponent("FactWidget", ({ widget }) => (
  <div className="fact">
    <BorderedFact
      borderColor="red"
      content={widget}
      attribute="value"
      className="value"
      tag="span"
    />
    <BorderedFact
      content={widget}
      attribute="key"
      className="key"
      tag="span"
    />
  </div>
));

This technique lets us pass any number of further props, in this case just borderColor, to our styled component. And, if we wanted to, we could also override the styles passed in via className. For example, to change the font color set by the value and key classes, we’d replace it by adding color: green !important; to the ”BorderdFact” component’s styles.

Note that we could also have made the color value configurable by editors. See Adding an Option to a Widget for details.

Passing widget or page content to styled components

If you already have a React app, e.g. one based on create-react-app, and are making heavy use of styled components, you might want to have them render Scrivito-based content.

Let’s once again take a look at the ”Button” component example above and figure out how we could pass the button text from within a widget component’s render method to it.

src/Widgets/ContactFormWidget/ContactFormWidgetComponent.js
Copy
const Button = styled.button`
  ...
`;

Scrivito.provideComponent("ContactFormWidget", ({ widget }) => {
  return(
    <Button>widget.get('buttonText')</Button>
  );
});

The content to be passed to a styled component can simply be retrieved using the widget.get method, or, with content that should be editable in place, using any of Scrivito’s helper components such as Scrivito.ContentTag. This analogously applies to page content.

Final words

Styled components are a great way to maintain and apply styles locally in your React components, which helps keeping stylesheets clear and focused on overall matters.

Scrivito page and widget components can be easily combined with styled components, whether you are integrating Scrivito with an existing React app, or just want to benefit from styled-components’ features such as dynamic styling or theming.