React Styled Components — Hooks, Refs, and Security

John Au-Yeung - Jan 23 '21 - - Dev Community

Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62

Subscribe to my email list now at http://jauyeung.net/subscribe/

React is the most used front end library for building modern, interactive front end web apps. It can also be used to build mobile apps.

In this article, we’ll look at how to access themes with hooks, referencing DOM elements with refs, and dealing with security.

Accessing Themes Using the useContext React Hook

We can use the useContext React hook with the ThemeContext to access theme properties with hooks.

For instance, we can do that as follows:

import React, { useContext } from "react";
import { ThemeProvider, ThemeContext } from "styled-components";

const baseTheme = {
  color: "green",
  backgroundColor: "white"
};

const Foo = ({ children }) => {
  const themeContext = useContext(ThemeContext);
  return <div style={themeContext}>{children}</div>;
};

export default function App() {
  return (
    <div>
      <ThemeProvider theme={baseTheme}>
        <Foo>foo</Foo>
      </ThemeProvider>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

In the code above, we used useContext with ThemeContext passed in to access the theme. themeContext has the exact same properties and values as baseTheme . Therefore, we can pass themeContext straight in as the value of the style prop.

In App , we wrapped ThemeProvider with theme set to baseTheme so that we can access the theme properties that are in baseTheme .

Therefore, we’ll see that ‘foo’ is displayed in green.

The theme Prop

We can pass themes down to child components with the theme prop. This works with components created with styled-components. For instance, we can do that as follows:

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

const Button = styled.button`
  font-size: 12px;
  margin: 5px;
  padding: 6px;
  border-radius: 3px;

color: ${props => props.theme.main};
  border: 2px solid ${props => props.theme.main};
`;

const theme = {
  main: "green"
};

export default function App() {
  return (
    <div>
      <ThemeProvider theme={theme}>
        <Button theme={{ main: "blue" }}>Foo</Button>
        <ThemeProvider theme={theme}>
          <div>
            <Button>Baz</Button>
            <Button theme={{ main: "red" }}>Bar</Button>
          </div>
        </ThemeProvider>
      </ThemeProvider>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

In the code above, we created a styled button with various styles. The colors are passed in from the theme and we access it with the prop.theme.main property.

Then in App , we use the theme prop to pass in different colors for some of the buttons. The Foo button is blue and the Bar button is red.

They will override the original color value that’s specified in theme , which is green .

Therefore, we’ll see buttons that have red, green or blue text border and color. Foo is blue, Baz is green, and Bar is red,

Refs

We can pass in refs to a styled component to access the DOM properties and methods for the given styled component.

For instance, we can do that as follows:

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

const Input = styled.input`
  padding: 0.5em;
  margin: 0.5em;
  background: greenyellow;
  border: none;
  border-radius: 3px;
`;

export default function App() {
  const inputRef = React.useRef();
  React.useEffect(() => {
    inputRef.current.focus();
  }, []);
  return (
    <div>
      <Input ref={inputRef} />
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

In the code above, we created a styled input called Input. Then we passed in a ref created with the useRef hook to Input .

Then in the useEffect callback, we call inputRef.current.focus(); to focus the element. The empty array in the 2nd argument of useEffect indicates that we load the callback when App first loads.

Therefore, when we first load the page, the Input will be focused on.

Photo by Icons8 Team on Unsplash

Security

Security is a concern when creating styled-components with styled-components because all the text is interpolated in our styled component if we pass them in via props, themes, or anywhere else.

Therefore, we should sanitize any input that’s passed in. For instance, the following would be bad:

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

const userInput = "/steal-money";

const ArbitraryComponent = styled.div`
  background: url(${userInput});
`;

export default function App() {
  return (
    <div>
      <ArbitraryComponent />
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

since we load the URL in our code, which isn’t good. Therefore, we should add some checks to avoid this from happening.

Conclusion

We can access themes with the useContext hook. Also, we can pass in the theme prop to pass in theme properties to override the values in the base theme.

styled-components will forward refs to our HTML element so that we can get the HTML element that’s in the styled component created with the package via the refs.

Finally, we should be careful when we’re interpolating strings in our styling code to avoid arbitrary code execution attacks.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .