React Styled Components — More Complex Selectors and Selectively Passing Props

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 creating styled-components with pseudo selectors and creating styled wrappers for other components.

Define Styled Components Outside of the Render Method

We can define styled-components outside of the render method with styled-components .

For instance, we can define a wrapper component as follows:

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

const StyledWrapper = styled.div`
  font-weight: bold;
`;

const Wrapper = ({ message }) => {
  return <StyledWrapper>{message}</StyledWrapper>;
};

export default function App() {
  return (
    <div className="App">
      <Wrapper message="foo" />
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

In the code above, we created the StyledWrapper component with its own styles. Then we created the Wrapper component which uses it. with the message prop passed inside. Then we can ass message as a prop to Wrapper used in App .

Therefore, we’ll see the word ‘foo’ bolded displayed on the screen.

Pseudoelements, Pseudoselectors, and Nesting

styled-components supports SCSS-like syntax for defining styles for a styled component. The preprocessor that uses for transforming CSS is stylis.

For instance, we can write the following code to define styles with props and stylis code as follows:

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

const Thing = styled.div.attrs(() => ({ tabIndex: 0 }))`
  color: blue;
  &:hover {
    color: red;
  }
  & ~ & {
    background: tomato;
  }
  & + & {
    background: lime;
  }
  &.foo {
    background: orange;
  }
  .foo & {
    border: 1px solid ${props => (props.primary ? "red" : "green")};
  }
`;

export default function App() {
  return (
    <div className="App">
      <Thing>foo</Thing>
      <Thing className="foo" primary>
        <Thing>abc</Thing>
        <Thing primary>abc</Thing>
        bar
      </Thing>
      <Thing className="bar">baz</Thing>
      <Thing>baz</Thing>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

In the code above, we have the Thing component, where we defined styles with pseudo selectors.

&:hover is the selector for when Thing is hovered.

& ~ & is the selector for the sibling of Thing but it may not be directly next to it.

& + & is the Thing next to a Thing .

&.foo is the Thing with a foo CSS class.

.foo & is the Thing inside something with the foo class. We also have a dynamic style with ${props => (props.primary ? “red” : “green”)} where we check for the primary prop and then apply the color accordingly.

Then we get the following colored text:

We can add the && pseudoselector to increase the specificity of the rules on the component.

For instance, we can write:

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

const Thing = styled.div`
  && {
    color: blue;
  }
`;

export default function App() {
  return (
    <div className="App">
      <Thing>foo</Thing>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Then we only apply the specified style to Thing . Therefore, we avoid conflicts with styles in other components with && .

Photo by Pineapple Supply Co. on Unsplash

Attaching Additional Props

We can pass in a callback to the attrs method so that we can choose the props that the base element receives. For instance, if we have an input and we want it to only receive the value attribute and the size prop, we can write:

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

const Input = styled.input.attrs(({ value, size }) => ({
  size,
  value
}))`
  color: palevioletred;
  font-size: 1em;
  margin: ${props => props.size};
  padding: ${props => props.size};
`;

export default function App() {
  return (
    <div className="App">
      <Input value="foo" size="5px" />
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

In the code above, we took the value andsize props and set them as attributes in the callback that we pass into the attrs method.

We also passed in the size prop into our styles dynamically in the string.

Then when we add the Input with the value set to 'foo' and size set to '5px' , then we’ll see those reflected in our styled input.

Conclusion

We can create styled components that are outside of the render method. Also, in addition to CSS selectors, we can use SCSS selectors for selecting elements.

The & selector is useful for selecting the current element. We can then use other selectors to select neighboring or child elements.

Also, we can use the && selector to select one specific element.

Finally, we can use the attrs method to selectively pass props as attribute values of components.

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