Adding transitions to styled components

26,180

Solution 1

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);
  `};
`;

Solution 2

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).

Solution 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>
Share:
26,180

Related videos on Youtube

H. Doe
Author by

H. Doe

Updated on December 30, 2020

Comments

  • H. Doe
    H. Doe over 3 years

    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.

    • Morpheus
      Morpheus almost 7 years
      Apply transition to the element itself, not the pseudo element. You do a transform on the element, but applying a transition to pseudo.
    • H. Doe
      H. Doe almost 7 years
      @Morpheus Tried, didn't work :(
    • Morpheus
      Morpheus almost 7 years
      I wonder if introducing the initial transform value would help, something like this jsfiddle.net/uhqx7enc
  • judehall
    judehall over 6 years
    +1 ${ props => props.expanded && css` transform: rotate(45deg);`}; Took me forever to find this. Thanks!