Animation
Animation is usually boiled down to three phases: enter, update, exit. With Reach UI you're probably just after the "enter" and "exit" phases.
You can achieve animation with CSS and/or composing with other React components. On this page we'll look at a few different approaches.
CSS Animations
You can animate the "enter" phase with just a little CSS.
@keyframes slide-down { 0% { opacity: 0; transform: translateY(-10px); } 100% { opacity: 1; transform: translateY(0); }} .slide-down[data-reach-menu-list],.slide-down[data-reach-menu-items] { border-radius: 5px;} @media (prefers-reduced-motion: no-preference) { .slide-down[data-reach-menu-list], .slide-down[data-reach-menu-items] { animation: slide-down 0.2s ease; }}
And then add the class to your menu:
function Example() { return ( <Menu> <MenuButton> Actions <span aria-hidden>▾</span> </MenuButton> <MenuList className="slide-down"> <MenuItem onSelect={() => {}}>Start Video</MenuItem> <MenuItem onSelect={() => {}}>Start Screenshare</MenuItem> <MenuItem onSelect={() => {}}>Send a Message</MenuItem> </MenuList> </Menu> );}
However, you can't animate the "exit" phase with just CSS because React removes the element from the DOM immediately.
CSS + reCONDITION Phase
You may want to use CSS for both the enter and exit phases. For this, we can combine some CSS with the Phased
component from reCONDITION.
First add the CSS to define the animation:
.slide-down { opacity: 0; transform: translateY(-10px);} .slide-down.enter { opacity: 1; transform: translateY(0px);} .slide-down.exit { opacity: 0;} @media (prefers-reduced-motion: no-preference) { .slide-down { transition-property: transform, opacity; transition-duration: 300ms; }}
Then import the Phased component:
import { Phased } from "recondition";
Now we're ready to go:
function Example() { // TODO: Update with Phased example return ( <Menu> <MenuButton> Actions <span aria-hidden>▾</span> </MenuButton> <MenuList className="slide-down"> <MenuItem onSelect={() => {}}>Start Video</MenuItem> <MenuItem onSelect={() => {}}>Start Screenshare</MenuItem> <MenuItem onSelect={() => {}}>Send a Message</MenuItem> </MenuList> </Menu> );}
React Spring
function Example(props) { const AnimatedDialogOverlay = animated(DialogOverlay); const AnimatedDialogContent = animated(DialogContent); const [showDialog, setShowDialog] = React.useState(false); const transitions = useTransition(showDialog, { from: { opacity: 0, y: -10 }, enter: { opacity: 1, y: 0 }, leave: { opacity: 0, y: 10 }, }); return ( <div> <button onClick={() => setShowDialog(true)}>Show Dialog</button> {transitions( (styles, item) => item && ( <AnimatedDialogOverlay style={{ opacity: styles.opacity }}> <AnimatedDialogContent style={{ transform: styles.y.to( (value) => `translate3d(0px, ${value}px, 0px)` ), border: "4px solid hsla(0, 0%, 0%, 0.5)", borderRadius: 10, }} > <button onClick={() => setShowDialog(false)}> Close Dialog </button> <p>React Spring makes it too easy!</p> <input type="text" /> <br /> <input type="text" /> <button>Ayyyyyy</button> </AnimatedDialogContent> </AnimatedDialogOverlay> ) )} </div> );}