Motion

Intentional use of snappy transitions and animations can give an app character, making it feel more responsive, performant, and lively.

Easing

Standard

Expand code

Standard easing can be used for basic transitions, like the background color for a button on hover, or a link's color changing on hover.

cubic-bezier(0.3, 0.75, 0.34, 0.95);

 

Entrance

Expand code

Entrance easing should be used when an object enters the screen, like a popup, modal overlay, or toast.

cubic-bezier(0, 0, 0.34, 0.95)

 

Exit

Expand code

Exit easing should be used when an object leaves the screen, like a popup, modal overlay, or toast.

cubic-bezier(0.3, 0.75, 1, 0.95);

 

 

Note: these were derived by averaging the productive and expressive easing curves from Carbon Design System's motion guidelines.

 

Duration

Animations and transitions should be fairly quick, typically between 0.15s and 0.3s, to keep the product feeling light and performant.

  • Standard transitions for interactive elements (e.g., button background) should last 0.15s.
  • More dramatic animations, like a modal or drawer entrance and exit, can last as long as 0.3s so it doesn't look quite as jarring.

Duration values

These are the duration values defined in src/ui/theme/motion.ts


                                                        
                                                        
                                                            export const duration = {
                                                          quick: '60ms',
                                                          short: '120ms',
                                                          medium: '200ms',
                                                          long: '300ms',
                                                          dramatic: '600ms',
                                                        };
                                                        
                                                            

Animation properties

Most animations can be made with a combination of four properties:

translate

A modal entry, for example, could have a 32px translate(Y)transition during entry and exit

scale

In places where a translate wouldn't make quite as much sense, we can use a very slight scale transition instead. A dropdown could transition from scale(0.95) to scale(1) on entrance, and the reverse on exit.

opacity

Used in conjunction with either translate or scale, this would typically translate from opacity: 0 to opacity: 1 on entry, and in the reverse for exit.

transform-origin

Consider using a transform-origin declaration to make the object interaction feel a little more natural and dynamic. If a dropdown menu is anchored to the right of its toggle, for example, we can usetransform-origin: top right;

Animation values

These are the animation values defined in src/ui/theme/motion.ts


                                                        
                                                        
                                                            export const fadeIn = keyframes`
                                                            0% {
                                                                opacity: 0;
                                                            }
                                                            100% {
                                                                opacity: 1;
                                                            }
                                                        `;
                                                        
                                                        export const fadeOut = keyframes`
                                                          from {
                                                            opacity: 1;
                                                          }
                                                          to {
                                                            opacity: 0;
                                                          }
                                                        `;
                                                        
                                                        export const slideUpFade = keyframes`
                                                        from {
                                                          opacity: 0;
                                                          transform: translateY(2px);
                                                        }
                                                        to {
                                                          opacity: 1;
                                                          transform: translateY(0);
                                                        }
                                                        `;
                                                        
                                                        export const slideDownFade = keyframes`
                                                          from {
                                                            opacity: 1;
                                                            transform: translateY(0);
                                                          }
                                                          to {
                                                            opacity: 0;
                                                            transform: translateY(2px);
                                                          }
                                                        `;
                                                        
                                                        export const slideRightFade = keyframes`
                                                        from {
                                                          opacity: 0;
                                                          transform: translateX(-4px);
                                                        }
                                                        to {
                                                          opacity: 1;
                                                          transform: translateX(0px);
                                                        }
                                                        `;