Skip Navigation
React Magma

Transition

Smart wrappers using framer-motion to add transitions to child components.

Basic Usage

The theme defines several preconfigured transitions that will apply the base styles and the exit and enter variants. Changing the value of isOpen results in the transition animating. Going from isOpen={true} to isOpen={false} will results in the transition animating to the exit variant. Going from isOpen={false} to isOpen={true} will result in animating to the enter variant.

Collapse

Collapse will transition the child components from 100% height to 0px.

import React from 'react';
import styled from '@emotion/styled';
import { Button, Transition } from 'react-magma-dom';
export function Example() {
const [isOpen, setIsOpen] = React.useState(false);
const Box = styled('div')`
height: 250px;
width: 250px;
background: #bada55;
`;
return (
<>
<Transition isOpen={isOpen} collapse>
<Box />
</Transition>
<Button onClick={() => setIsOpen(!isOpen)}>
{isOpen ? 'hide' : 'show'}
</Button>
</>
);
}

Fade

To have the child components fade from completely transparent use the fade transition.

import React from 'react';
import styled from '@emotion/styled';
import { Button, Transition } from 'react-magma-dom';
export function Example() {
const [isOpen, setIsOpen] = React.useState(false);
const Box = styled('div')`
height: 250px;
width: 250px;
background: #bada55;
`;
return (
<>
<Transition isOpen={isOpen} fade>
<Box />
</Transition>
<Button onClick={() => setIsOpen(!isOpen)}>
{isOpen ? 'hide' : 'show'}
</Button>
</>
);
}

Nudge

The Nudge transitions (nudgeLeft, nudgeRight, nudgeTop, nudgeBottom) move the children from 50px away from their target. Alone this might look weird, but when used in conjection with fade it gives the apparence of fading into a closer position.

import React from 'react';
import styled from '@emotion/styled';
import { Button, Transition } from 'react-magma-dom';
export function Example() {
const [isOpen, setIsOpen] = React.useState(false);
const Box = styled('div')`
height: 250px;
width: 250px;
background: #bada55;
`;
return (
<>
<Transition isOpen={isOpen} nudgeLeft style={{ margin: '0 0 10px 50px' }}>
<Box />
</Transition>
<Button onClick={() => setIsOpen(!isOpen)}>
{isOpen ? 'hide' : 'show'}
</Button>
</>
);
}

Rotate

The rotate transitions (rotate45, rotate90, rotate180) will rotate the child components counter-clockwise.

import React from 'react';
import styled from '@emotion/styled';
import { Button, Transition } from 'react-magma-dom';
export function Example() {
const [isOpen, setIsOpen] = React.useState(false);
const Box = styled('div')`
height: 250px;
width: 50px;
margin: 0 auto;
background: #bada55;
`;
return (
<>
<Transition
isOpen={isOpen}
style={{ width: '250px', height: '250px' }}
rotate45
>
<Box />
</Transition>
<Button onClick={() => setIsOpen(!isOpen)}>rotate</Button>
</>
);
}

Scale

The scale transition will scale the child components from 95% to 100%. This alone will not look impressive, but when used with fade creates a nice transition.

import React from 'react';
import styled from '@emotion/styled';
import { Button, Transition } from 'react-magma-dom';
export function Example() {
const [isOpen, setIsOpen] = React.useState(false);
const Box = styled('div')`
height: 250px;
width: 250px;
background: #bada55;
margin: 0 auto;
`;
return (
<>
<Transition isOpen={isOpen} style={{ width: '250px' }} scale>
<Box />
</Transition>
<Button onClick={() => setIsOpen(!isOpen)}>
{isOpen ? 'shrink' : 'grow'}
</Button>
</>
);
}

Slide

The slide transitions (slideRight, slideLeft, slideTop, slideBottom) will slide the children to the edge of the screen from outside of view. The slide transitions will always anchor the children to one of the edges of the screen.

import React from 'react';
import styled from '@emotion/styled';
import { Button, Transition } from 'react-magma-dom';
export function Example() {
const [isOpen, setIsOpen] = React.useState(false);
const Box = styled('div')`
height: 100%;
width: 250px;
background: #bada55;
`;
return (
<>
<Transition isOpen={isOpen} slideLeft>
<Box />
</Transition>
<Button onClick={() => setIsOpen(!isOpen)}>
{isOpen ? 'hide' : 'show'}
</Button>
</>
);
}

Composition

Transitions can be combined to create more advanced effects.

import React from 'react';
import styled from '@emotion/styled';
import { Button, Transition } from 'react-magma-dom';
export function Example() {
const [isOpen, setIsOpen] = React.useState(false);
const Box = styled('div')`
height: 250px;
width: 250px;
background: #bada55;
`;
return (
<>
<Transition isOpen={isOpen} nudgeBottom fade>
<Box />
</Transition>
<Button onClick={() => setIsOpen(!isOpen)}>
{isOpen ? 'hide' : 'show'}
</Button>
</>
);
}

unmountOnExit

By default, Transition will only transition between the two style variants for enter and exit but will leave the children in the DOM. Using the prop unmountOnExit will remove the children from the DOM completely after they have been animated off the visible screen.

import React from 'react';
import styled from '@emotion/styled';
import { Button, Transition } from 'react-magma-dom';
export function Example() {
const [isOpen, setIsOpen] = React.useState(false);
const Box = styled('div')`
height: 250px;
width: 250px;
background: #bada55;
`;
return (
<>
<Transition isOpen={isOpen} collapse unmountOnExit>
<Box />
</Transition>
<Button onClick={() => setIsOpen(!isOpen)}>
{isOpen ? 'hide' : 'show'}
</Button>
</>
);
}

Custom Transition

The magma theme has several sane defaults to create a consistent experience across all apps. But Transition does allow for customTransition and style to be overwritten.

import React from 'react';
import styled from '@emotion/styled';
import { Button, Transition } from 'react-magma-dom';
export function Example() {
const [isOpen, setIsOpen] = React.useState(false);
const Box = styled('div')`
height: 250px;
width: 250px;
background: #bada55;
`;
const customTransition = {
exit: {
rotate: 360,
transition: {
rotate: {
type: 'inertia',
velocity: 500,
},
},
},
enter: {
rotate: 0,
transition: {
rotate: {
type: 'spring',
damping: 10,
stiffness: 100,
},
},
},
};
const baseStyle = {
width: '250px',
height: '250px',
};
return (
<>
<Transition
style={baseStyle}
isOpen={isOpen}
customTransition={customTransition}
>
<Box />
</Transition>
<Button onClick={() => setIsOpen(!isOpen)}>Spin it!</Button>
</>
);
}

Kitchen Sink

import React from 'react';
import styled from '@emotion/styled';
import { Button, Transition, Checkbox } from 'react-magma-dom';
export function Example() {
const [isOpen, setIsOpen] = React.useState(false);
const [properties, setProperties] = React.useState({});
const Box = styled('div')`
height: 250px;
width: 250px;
background: #bada55;
`;
const Preview = () => (
<pre>
{'<'}Transition{' '}
{Object.keys(properties)
.filter(key => properties[key])
.join(' ')}
{'>\n'}
{' <'}div{'>'}children{'<'}/div{'>\n'}
{'<'}/Transition{'>'}
</pre>
);
return (
<>
<Checkbox
labelText="unmountOnExit"
checked={properties.unmountOnExit}
onChange={() =>
setProperties({
...properties,
unmountOnExit: !properties.unmountOnExit,
})
}
/>
<Checkbox
labelText="fade"
checked={properties.fade}
onChange={() =>
setProperties({ ...properties, fade: !properties.fade })
}
/>
<Checkbox
labelText="scale"
checked={properties.scale}
onChange={() =>
setProperties({ ...properties, scale: !properties.scale })
}
/>
<Checkbox
labelText="collapse"
checked={properties.collapse}
disabled={
properties.slideTop |
properties.slideBottom |
properties.slideLeft |
properties.slideRight |
properties.nudgeTop |
properties.nudgeBottom |
properties.nudgeLeft |
properties.nudgeRight
}
onChange={() =>
setProperties({ ...properties, collapse: !properties.collapse })
}
/>
<Checkbox
labelText="slideTop"
checked={properties.slideTop}
disabled={
properties.collapse |
properties.slideBottom |
properties.slideLeft |
properties.slideRight |
properties.nudgeTop |
properties.nudgeBottom |
properties.nudgeLeft |
properties.nudgeRight
}
onChange={() =>
setProperties({ ...properties, slideTop: !properties.slideTop })
}
/>
<Checkbox
labelText="slideBottom"
checked={properties.slideBottom}
disabled={
properties.collapse |
properties.slideTop |
properties.slideLeft |
properties.slideRight |
properties.nudgeTop |
properties.nudgeBottom |
properties.nudgeLeft |
properties.nudgeRight
}
onChange={() =>
setProperties({
...properties,
slideBottom: !properties.slideBottom,
})
}
/>
<Checkbox
labelText="slideRight"
checked={properties.slideRight}
disabled={
properties.collapse |
properties.slideTop |
properties.slideBottom |
properties.slideLeft |
properties.nudgeTop |
properties.nudgeBottom |
properties.nudgeLeft |
properties.nudgeRight
}
onChange={() =>
setProperties({
...properties,
slideRight: !properties.slideRight,
})
}
/>
<Checkbox
labelText="slideLeft"
checked={properties.slideLeft}
disabled={
properties.collapse |
properties.slideTop |
properties.slideBottom |
properties.slideRight |
properties.nudgeTop |
properties.nudgeBottom |
properties.nudgeLeft |
properties.nudgeRight
}
onChange={() =>
setProperties({ ...properties, slideLeft: !properties.slideLeft })
}
/>
<Checkbox
labelText="nudgeTop"
checked={properties.nudgeTop}
disabled={
properties.collapse |
properties.slideTop |
properties.slideBottom |
properties.slideLeft |
properties.slideRight |
properties.nudgeBottom
}
onChange={() =>
setProperties({ ...properties, nudgeTop: !properties.nudgeTop })
}
/>
<Checkbox
labelText="nudgeBottom"
checked={properties.nudgeBottom}
disabled={
properties.collapse |
properties.slideTop |
properties.slideBottom |
properties.slideLeft |
properties.slideRight |
properties.nudgeTop
}
onChange={() =>
setProperties({
...properties,
nudgeBottom: !properties.nudgeBottom,
})
}
/>
<Checkbox
labelText="nudgeRight"
checked={properties.nudgeRight}
disabled={
properties.collapse |
properties.slideTop |
properties.slideBottom |
properties.slideLeft |
properties.slideRight |
properties.nudgeLeft
}
onChange={() =>
setProperties({
...properties,
nudgeRight: !properties.nudgeRight,
})
}
/>
<Checkbox
labelText="nudgeLeft"
checked={properties.nudgeLeft}
disabled={
properties.collapse |
properties.slideTop |
properties.slideBottom |
properties.slideLeft |
properties.slideRight |
properties.nudgeRight
}
onChange={() =>
setProperties({ ...properties, nudgeLeft: !properties.nudgeLeft })
}
/>
<Preview />
<Transition isOpen={isOpen} {...properties}>
<Box />
</Transition>
<Button onClick={() => setIsOpen(!isOpen)}>
{isOpen ? 'hide' : 'show'}
</Button>
</>
);
}

Transition Props

Any other props supplied will be provided to the wrapping motion.div element.

collapse

Description

Should children collapse in/out

Type

boolean

Default

false


fade

Description

Should children fade in/out

Type

boolean

Default

false


isOpen

Description

If `true`, the content will animate in

Type

boolean

Default

false


nudgeBottom

Description

Should the children get nudged in 50px from the bottom

Type

boolean

Default

false


nudgeLeft

Description

Should the children get nudged in 50px from the left

Type

boolean

Default

false


nudgeRight

Description

Should the children get nudged in 50px from the right

Type

boolean

Default

false


nudgeTop

Description

Should the children get nudged in 50px from the top

Type

boolean

Default

false


rotate180

Description

Should children rotate 180 degrees

Type

boolean

Default

false


rotate45

Description

Should children rotate 45 degrees

Type

boolean

Default

false


rotate90

Description

Should children rotate 90 degrees

Type

boolean

Default

false


scale

Description

Should children scale in/out

Type

boolean

Default

false


slideBottom

Description

Should children slide in/out from the bottom of the screen

Type

boolean

Default

false


slideLeft

Description

Should children slide in/out from the left of the screen

Type

boolean

Default

false


slideRight

Description

Should children slide in/out from the right of the screen

Type

boolean

Default

false


slideTop

Description

Should children slide in/out from the top of the screen

Type

boolean

Default

false


unmountOnExit

Description

If `true`, the element will unmount when `in={false}` and animation is done

Type

boolean

Default

false


On this page

Deploys by Netlify