React hooks for the document transition API
React Document Transitions
This package enables creating complex state transitions by using simple hooks. It uses document.createDocumentTransition
from the page transition API. This API is currently only available in Chrome Canary.
Basic Usage
The useTransitionState
hook is a thin wrapper around the useState
hook and exposes a nearly identical API.
import React, { useState } from 'react';
import { useTransitionState } from 'react-document-transition';
function Example() {
const [count, setCount] = useTransitionStat(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
However, in browsers which support the document.createDocumentTransition
API, any state changes will be animated.
Advanced Usage
import { useTransitionState } from 'react-document-transition';
type TodoItem = {
name: string;
done: boolean;
}
type TodoListState = {
items: TodoItem[],
}
function Item(item: TodoItem & { toggle: (item: TodoItem) => void}) {
const slug = item.name.replaceAll(" ", "-").toLowerCase();
const toggle = () => {
item.toggle(item);
};
return (
<div
onClick={toggle}
className={`item ${item.done ? 'done' : ''}`}
style={{
pageTransitionTag: slug,
} as React.CSSProperties}
>
<h1>{item.name}</h1>
</div>
);
}
function App() {
const [state, setState] = useTransitionState<TodoListState>({
items: [
{ done: false, name: "Buy Milk" },
{ done: false, name: "Publish NPM Package" },
{ done: false, name: "Become Rich and Famous" },
{ done: true, name: "Pay Rent" },
{ done: true, name: "Create React Document Transition Hook" },
],
});
function toggle(item: TodoItem) {
let items: TodoItem[] = Array.from(state.items);
const foundItem = items.find(maybeItem => maybeItem.name === item.name);
if (foundItem) {
foundItem.done = !foundItem.done;
}
setState({
items,
});
}
return (
<div className="App">
<div className="todo-col">
{state.items.filter(item => !item.done).map((item) => (
<Item {...item} toggle={toggle} key={item.name} />
))}
</div>
<div className="done-col">
{state.items.filter(item => item.done).map((item) => (
<Item {...item} toggle={toggle} key={item.name} />
))}
</div>
</div>
);
}
export default App;
.App {
text-align: center;
display: flex;
min-height: 100vh;
}
.todo-col {
display: flex;
flex-direction: column;
row-gap: 12px;
padding: 12px;
flex: 1;
background: red;
}
.done-col {
display: flex;
flex-direction: column;
row-gap: 12px;
padding: 12px;
flex: 1;
background: green;
}
.item {
contain: paint;
background: lightpink;
border-radius: 12px;
cursor: pointer;
}
.item.done {
background: lightblue;
}
.item.done h1 {
font-size: 16px;
}