23

I have following component in React:

const Button = styled.div`
        width: 30px;
        height: 30px;
        position: absolute;
        right: 2em;
        top: 50%;
        transform: translateY(-50%);
        padding: 0;
        margin: 0;

        &::before,
        &::after {
          content: "";
          position: absolute;
          background-color: #3d3935;
          transition: transform 0.25s ease-out;
        }

        &::before {
          top: 0;
          left: 50%;
          width: 4px;
          height: 100%;
          margin-left: -2px;
        }

        &::after {
          top: 50%;
          left: 0;
          width: 100%;
          height: 4px;
          margin-top: -2px;
        }
`;

It just renders a component with library Styled-components. It basically shows a + sign.

But then, I would like to rotate each of the lines separately, using:

    &::before {
      transform: rotate(${this.state.expanded ? '0' : '45'}deg);
    }
    &::after {
      transform: rotate(${this.state.expanded ? '0' : '135'}deg);
    }

And it works great, but unfortunately there are no transitions (it happens immediately). Tried to include transitions in each of these lines, but it still doesn't affect the changes.

Another solution which I've tried was to add a class, e.g. rotated:

    &.rotated::before {
      transform: rotate(45deg);
    }

But styled components doesn't provide actually possibility to change classes dynamically using just it's logic.

Looking forward for any kind of help, thank you.

Chris
  • 57,622
  • 19
  • 111
  • 137
H. Doe
  • 545
  • 2
  • 5
  • 12

3 Answers3

34

You can try passing a conditional props to the component.

import styled, { css } from 'styled-components';

<Button expanded={ this.state.expanded } />

And then in you SC:

const Button = styled.div`
  transform: rotate(0deg);
  transition: transform .2s ease-out;

  ${ props => props.expanded && css`
    transform: rotate(45deg);
  `};
`;
chh
  • 850
  • 1
  • 9
  • 11
  • 2
    +1 ${ props => props.expanded && css` transform: rotate(45deg);`}; Took me forever to find this. Thanks! – judehall Dec 21 '17 at 23:09
5

You can also use a ternary operator:

const Button = styled.div`
  transform: ${props => props.expanded ? 'rotate(180deg)' : 'rotate(0deg)'};
  transition: transform .2s ease-out;
`;

Also make sure to define the Button outside the function you are using it in. Made that mistake right now, and didn't understand why the transition didn't work (tips for future me).

Jonas Sandstedt
  • 1,160
  • 11
  • 12
3

I was struggling with this for a while, I got it to work by doing this:

import styled from 'styled-components';
import { IconButton } from '@material-ui/core';
import { Pin } from 'styled-icons/boxicons-solid/Pin';

const IconWrapper = styled(IconButton).attrs(props => ({
  style: {
   padding: '0',
   transition: 'transform 0.2s ease-out',
   transform: props.rotated ? 'rotate(0)' : 'rotate(90deg)',
  },
}))`
  /* additional css goes here */
`;

Then in the return:

<IconWrapper
  rotated={isRotated}
  onClick={handleClick} /* toggle isRotated true/false */
>
  <Pin size="20" />
</IconWrapper>
Brandon
  • 31
  • 4