React Showtime makes it easy to apply CSS transitions to the appearance and disappearance of React elements. It automatically handles mounting and unmounting to allow time for transitions to occur.
Demo: https://react-showtime.dev/
👯 Choose between useShowtime
hook and <Showtime />
component.
💃 Feels familiar: useShowtime
is a near-drop-in replacement for conditional rendering with a state boolean.
💅 Specify showing styles however you like – inline, emotion, styled-components, classnames, you name it.
💨 Sensible API for defining hidden styles and custom transitions.
🎩 Included transitions: slideFade
, slide
, fade
, rise
, scale
.
🎭 Symmetric or asymmetric show/hide transitions.
🕴 Zero dependencies. 3.4k min+gzip.
The essential insight of React Showtime is that the one-two sequence of React's useLayoutEffect
and useEffect
hooks is nicely suited to the one-two sequence of mounting a component with hidden CSS values and then applying showing CSS values to trigger the transition. As for hiding, transition event handlers trigger unmounting once the "hide" transition is complete.
React Showtime is not for transitions that do not involve mounting/unmounting. It was created specifically as a shim for conditional rendering.
React Showtime is not for sophisticated animations, as it executes via CSS transition
, not animation
. Consider a more full-featured library like react-spring if you need keyframes or additional sophistication.
yarn add react-showtime
npm install react-showtime
- Choose between the
useShowtime
hook or theShowtime
component. The component is better for list items or if you need to listen for events (onShowing
,onHidden
). - Define your
transition
by describing the item's hidden styles with a CSS object literal. Or just pass the name of an included transition (slideFade
,slide
,fade
,rise
,scale
). - If using the hook, attach the supplied
ref
to your containing element and conditionally render your item with the suppliedisMounted
boolean. - Call the hook's
show()
andhide()
functions – or toggle the component'sshow
prop – as needed.
Optionally adjust transition timing via duration
, delay
, easing
.
You can also define asymmetric show/hide transitions (showTransition
, hideTransition
) and timing (showDuration
, showDelay
, showEasing
, hideDuration
, hideDelay
, hideEasing
).
As a rule of thumb, since you can't call hooks inside loops, use the hook when dealing with a singleton item that needs to conditionally appear or disappear (eg, a notification), and use the component when you've an indeterminate set of children that need to individually transition in and out of the DOM (eg, a list of messages).
The hook is designed to integrate with React's conditional rendering idiom. It returns an array/object containing a ref
that must be attached to your element or component, an isMounted
boolean that will conditionally render it, and show()
and hide()
functions for you to call as needed.
import React from "react";
import { useShowtime } from "react-showtime";
const HookExample = () => {
const [ref, isMounted, show, hide] = useShowtime();
// Or use object destructuring...
// const {ref, isMounted, show, hide} = useShowtime();
const toggle = () => (isMounted ? hide() : show());
return (
<div>
<button onClick={toggle}>Toggle</button>
{isMounted && <div ref={ref}>Hi there</div>}
</div>
);
};
Your element or component will start off showing by default. Pass { startHidden: true }
to override that.
Pass { startWithTransition: true }
to automatically execute the show
transition when the item initially mounts. It will be ignored if startHidden
is true
.
Showtime
takes a single child component. It uses useShowtime
under the hood, cloning the child and adding the ref
to it.
Toggle the show
boolean prop to trigger show/hide.
import React, { useState } from "react";
import { Showtime } from "react-showtime";
const ComponentExample = () => {
const [show, setShow] = useState(true);
const toggle = () => setShow((current) => !current);
return (
<div>
<button onClick={toggle}>Toggle</button>
<Showtime show={show}>
<div>Oh hi</div>
</Showtime>
</div>
);
};
Pass startWithTransition={true}
to automatically execute the show
transition when the item initially mounts. It will be ignored if show
is initially set to false
.
Since Showtime
clones the child to attach its ref
, it may be an expensive operation in some cases if the child component is substantially complicated. If so, provide a function that takes a ref
and returns the child component instead, which may be more performant:
import React, { useState } from "react";
import { Showtime } from "react-showtime";
const ComponentExample = () => {
const [show, setShow] = useState(true);
const toggle = () => setShow((current) => !current);
return (
<div>
<button onClick={toggle}>Toggle</button>
<Showtime show={show}>
{(ref) => <div ref={ref}>Oh hi</div>}
</Showtime>
</div>
);
};
However, the direct child specification is recommended for most users.
If you accept all defaults, you'll get a slideFade
transition with a 250ms
duration, 16ms
delay, and "ease"
easing:
// Hook
const [ref, isMounted, show, hide] = useShowtime();
// Component
<Showtime show={true}>...</Showtime>
React Showtime includes a set of pre-configured transitions: slideFade
, slide
, fade
, rise
, scale
.
Choose one by passing its name as the hook's sole parameter or to the component's transition
prop.
// Hook
const [ref, isMounted, show, hide] = useShowtime("slide");
// Component
<Showtime transition="fade" show={true}>
...
</Showtime>
The hook also accepts an object instead of a string, in which case pass { transition: ... }
:
const [ref, isMounted, show, hide] = useShowtime({ transition: "slide" });
Adjust the transition's timing via duration
, delay
, and easing
.
duration
and delay
accept integers (interpreted as milliseconds
), floats (interpreted as seconds
), or strings (eg, "1s"
or "300ms"
.)
easing
accepts any valid CSS transition-timing-function
value.
// Hook
const [ref, isMounted, show, hide] = useShowtime({
transition: "rise",
duration: 1000,
delay: 250,
easing: "linear",
});
// Component
<Showtime
show={true}
transition="scale"
duration={500}
delay={50}
easing="ease-out"
>
If you need different timings across show and hide transitions, use showDuration
, showDelay
, showEasing
, and hideDuration
, hideDelay
, hideEasing
.
To define a custom transition, pass a CSS object literal describing the item's hidden state to the transition
prop(erty).
Each value can be a string, number, or object. Strings and numbers will be passed through as CSS.
As an example, here's how you might define a revolve transition, where showing would mount the item then fade it in while spinning it around the y-axis. Hiding would do the reverse.
// Hook
const [ref, isMounted, show, hide] = useShowtime({
transition: {
transform: "rotate3d(0, 1, 0, 180deg)",
opacity: 0,
},
...
});
// Component
<Showtime
transition={{
transform: "rotate3d(0, 1, 0, 180deg)",
opacity: 0,
}}
...
>
You can pass an object instead of a string or number as a CSS property's value. It should contain { value, duration, delay, easing }
properties.
value
is required and will be passed through as the CSS property's value.
The other properties are optional and will be applied to that property's transition timing, overriding any inherited timing values.
In this example, the right
and top
CSS properties will have a 350ms
transition duration and the default "ease"
easing, while opacity
will take 400ms
using "linear"
easing.
const HookExample = () => {
const [ref, isMounted, show, hide] = useShowtime({
duration: 350,
transition: {
right: "100vw",
top: "-100vh",
opacity: {
value: 0,
duration: 400,
easing: "linear",
},
},
});
// ...
};
The showTransition
and hideTransition
properties allow you to use different transitions for showing and hiding. This is useful if, say, a notification should slide down from above, but fade away when dismissed.
Like transition
, these properties accept a string (included transition) or object (custom transition). They override transition
if that's also passed in.
const HookExample = () => {
const [ref, isMounted, show, hide] = useShowtime({
showTransition: "fade",
hideTransition: {
right: "100vw",
top: "-100vh",
opacity: 0,
},
hideDuration: 350,
});
// ...
};
The useShowtime
hook provides a ref
that must end up attached to the element you're showing/hiding. It uses the ref
to directly assign CSS transition properties and hidden styles to the element, and to listen for transition events.
If you are transitioning an element directly, you can just pass the provided ref
as a prop.
If you are transitioning a custom component, consider updating the component to use ref forwarding to pass the ref
down to the component's outermost element.
If you are transitioning a component you cannot edit and that does not forward refs to its outermost element, attach the ref
to a wrapper div.
There may be times when you need to attach your own ref
to the element or component, along with React Showtime's ref
. You can do this using a callback ref.
import React, { useRef } from "react";
import { useShowtime } from "react-showtime";
const MultipleRefsExample = () => {
const myRef = useRef();
const [showtimeRef, isMounted, show, hide] = useShowtime();
const setRefs = (node) => {
myRef.current = node;
showtimeRef.current = node;
};
const toggle = () => (isMounted ? hide() : show());
return (
<>
<button onClick={toggle}>Toggle</button>
{isMounted && <div ref={setRefs}>Hi there</div>}
</>
);
};
If you pass a function child to the Showtime
component (aka render prop), you can use a similar solution as the above to attach both your own ref
and the ref
Showtime supplies to the function child.
If you pass a normal JSX child to the Showtime
component, the implementation is robust to any normal or callback ref
you might attach yourself. Eg, in the following code, myRef
will be attached as expected, along with the ref
that Showtime
attaches internally.
import React, { useRef } from "react";
import { Showtime } from "react-showtime";
const MultipleRefsExample = () => {
const myRef = useRef();
const [show, setShow] = useState(true);
const toggle = () => setShow((current) => !current);
return (
<>
<button onClick={toggle}>Toggle</button>
<Showtime show={show}>
<div ref={myRef}>Hi there</div>
</Showtime>
</>
);
};
The Showtime
component accepts handlers for onHidden
and onShowing
. Other lifecycle events are being considered.
The useShowtime
hook currently does not accept any event handlers.
All timing-related numbers are interpreted as milliseconds
if integer, and seconds
if float.
The useShowtime
hook accepts a single parameter, which can be either of:
- a string referring to an included transition
- an object with the following properties:
Name | Type | Req'd | Default | Description |
---|---|---|---|---|
startHidden |
boolean |
no | false |
Hide the element initially |
startWithTransition |
boolean |
no | false |
Execute show transition on initial mount. Ignored if startHidden is true . |
transition |
string or CSS Properties |
no | "slideFade" |
Included transition or object defining custom transition (see below) |
showTransition |
string or CSS Properties |
no | "slideFade" |
Included transition or object defining custom transition (see below) |
hideTransition |
string or CSS Properties |
no | "slideFade" |
Included transition or object defining custom transition (see below) |
duration |
number or string |
no | 250 |
Transition duration |
delay |
number or string |
no | 16 |
Transition delay |
easing |
string |
no | "ease" |
Transition timing function |
showDuration |
number or string |
no | Transition duration | |
showDelay |
number or string |
no | Transition delay | |
showEasing |
string |
no | Transition timing function | |
hideDuration |
number or string |
no | Transition duration | |
hideDelay |
number or string |
no | Transition delay | |
hideEasing |
string |
no | Transition timing function |
Name | Type | Req'd | Default | Description |
---|---|---|---|---|
show |
boolean |
yes | Toggle this to show/hide the element or component | |
startWithTransition |
boolean |
no | false |
Execute show transition on initial mount. Ignored if show initially set to false . |
transition |
string or CSS Properties |
no | "slideFade" |
Included transition or object defining custom transition (see below) |
showTransition |
string or CSS Properties |
no | "slideFade" |
Included transition or object defining custom transition (see below) |
hideTransition |
string or CSS Properties |
no | "slideFade" |
Included transition or object defining custom transition (see below) |
duration |
number or string |
no | 250 |
Transition duration |
delay |
number or string |
no | 16 |
Transition delay |
easing |
string |
no | "ease" |
Transition timing function |
showDuration |
number or string |
no | Transition duration | |
showDelay |
number or string |
no | Transition delay | |
showEasing |
string |
no | Transition timing function | |
hideDuration |
number or string |
no | Transition duration | |
hideDelay |
number or string |
no | Transition delay | |
hideEasing |
string |
no | Transition timing function | |
onHidden |
function |
no | Called when hide transition complete. | |
onShowing |
function |
no | Called when show transition complete. |
Name | Type | Req'd | Default | Description |
---|---|---|---|---|
[Any CSS property name] | string , number , or CSS Property |
yes | Use camelCase for names. String and number values passed directly to style. |
Name | Type | Req'd | Default | Description |
---|---|---|---|---|
value |
string or number |
yes | Any CSS property name. | |
duration |
number or string |
no | inherited | Transition duration |
delay |
number or string |
no | inherited | Transition delay |
easing |
string |
no | inherited | Transition timing function |
React Showtime was originally bootstrapped with create-react-hook using this blog post as a guiding reference.
Be sure to reflect any API changes in test fixtures, the demo app in example/
, the TypeScript types in index.d.ts
, and this readme.
To get started:
yarn start
to watch for local changes toreact-showtime
,yarn start
inexample/
to watch for changes to the demo site and run a dev server.
This project uses the Git Flow branching workflow. Usage of the gitflow-cjs
CLI tool is recommended for releases and hotfixes.