0
# Transition Groups
1
2
Animation and transition components for managing component lifecycle animations and CSS transitions.
3
4
## Capabilities
5
6
### Transition Group
7
8
Container component that manages entering and leaving transitions for its children.
9
10
```javascript { .api }
11
/**
12
* Container for managing child component transitions
13
*/
14
class TransitionGroup extends Component {
15
/**
16
* TransitionGroup props
17
*/
18
props: {
19
/** Component type to render as (default: 'span') */
20
component?: string | ComponentType;
21
22
/** Additional props passed to component */
23
[key: string]: any;
24
};
25
}
26
27
/**
28
* CSS-based transition group with automatic class management
29
*/
30
class CSSTransitionGroup extends Component {
31
/**
32
* CSSTransitionGroup props
33
*/
34
props: {
35
/** Base name for CSS classes */
36
transitionName: string | TransitionClasses;
37
38
/** Enter transition duration in ms */
39
transitionEnterTimeout: number;
40
41
/** Leave transition duration in ms */
42
transitionLeaveTimeout: number;
43
44
/** Whether to apply transition on initial mount */
45
transitionAppear?: boolean;
46
47
/** Appear transition duration in ms */
48
transitionAppearTimeout?: number;
49
50
/** Component type to render as (default: 'span') */
51
component?: string | ComponentType;
52
53
/** Additional props passed to component */
54
[key: string]: any;
55
};
56
}
57
58
/**
59
* CSS class names for different transition states
60
*/
61
interface TransitionClasses {
62
enter: string;
63
enterActive: string;
64
leave: string;
65
leaveActive: string;
66
appear?: string;
67
appearActive?: string;
68
}
69
```
70
71
**Usage Examples:**
72
73
```javascript
74
import { CSSTransitionGroup } from 'preact-compat';
75
// or
76
import { CSSTransitionGroup } from 'preact-compat/lib/ReactTransitionGroup';
77
78
class TodoList extends Component {
79
state = {
80
todos: [
81
{ id: 1, text: 'Learn React' },
82
{ id: 2, text: 'Build an app' }
83
]
84
};
85
86
addTodo = () => {
87
const newTodo = {
88
id: Date.now(),
89
text: `Todo ${this.state.todos.length + 1}`
90
};
91
92
this.setState({
93
todos: [...this.state.todos, newTodo]
94
});
95
};
96
97
removeTodo = (id) => {
98
this.setState({
99
todos: this.state.todos.filter(todo => todo.id !== id)
100
});
101
};
102
103
render() {
104
return (
105
<div>
106
<button onClick={this.addTodo}>Add Todo</button>
107
108
<CSSTransitionGroup
109
transitionName="todo"
110
transitionEnterTimeout={300}
111
transitionLeaveTimeout={300}
112
component="ul"
113
>
114
{this.state.todos.map(todo => (
115
<li key={todo.id}>
116
{todo.text}
117
<button onClick={() => this.removeTodo(todo.id)}>
118
Remove
119
</button>
120
</li>
121
))}
122
</CSSTransitionGroup>
123
</div>
124
);
125
}
126
}
127
```
128
129
### CSS Classes and Animations
130
131
```css
132
/* CSS for the example above */
133
134
/* Enter transition */
135
.todo-enter {
136
opacity: 0;
137
transform: translateX(-100%);
138
}
139
140
.todo-enter-active {
141
opacity: 1;
142
transform: translateX(0);
143
transition: all 300ms ease-in;
144
}
145
146
/* Leave transition */
147
.todo-leave {
148
opacity: 1;
149
transform: translateX(0);
150
}
151
152
.todo-leave-active {
153
opacity: 0;
154
transform: translateX(100%);
155
transition: all 300ms ease-out;
156
}
157
158
/* Appear transition (optional) */
159
.todo-appear {
160
opacity: 0;
161
transform: scale(0.8);
162
}
163
164
.todo-appear-active {
165
opacity: 1;
166
transform: scale(1);
167
transition: all 300ms ease-in-out;
168
}
169
```
170
171
### Custom Transition Classes
172
173
```javascript
174
import { CSSTransitionGroup } from 'preact-compat';
175
176
const customTransitions = {
177
enter: 'slide-in',
178
enterActive: 'slide-in-active',
179
leave: 'slide-out',
180
leaveActive: 'slide-out-active',
181
appear: 'fade-in',
182
appearActive: 'fade-in-active'
183
};
184
185
function AnimatedList({ items }) {
186
return (
187
<CSSTransitionGroup
188
transitionName={customTransitions}
189
transitionEnterTimeout={500}
190
transitionLeaveTimeout={500}
191
transitionAppear={true}
192
transitionAppearTimeout={500}
193
component="div"
194
className="animated-container"
195
>
196
{items.map(item => (
197
<div key={item.id} className="animated-item">
198
{item.content}
199
</div>
200
))}
201
</CSSTransitionGroup>
202
);
203
}
204
```
205
206
### Modal with Transitions
207
208
```javascript
209
import { CSSTransitionGroup } from 'preact-compat';
210
211
class Modal extends Component {
212
render() {
213
const { isOpen, onClose, children } = this.props;
214
215
return (
216
<CSSTransitionGroup
217
transitionName="modal"
218
transitionEnterTimeout={200}
219
transitionLeaveTimeout={200}
220
component="div"
221
>
222
{isOpen && (
223
<div key="modal" className="modal-backdrop" onClick={onClose}>
224
<div className="modal-content" onClick={e => e.stopPropagation()}>
225
<button className="modal-close" onClick={onClose}>×</button>
226
{children}
227
</div>
228
</div>
229
)}
230
</CSSTransitionGroup>
231
);
232
}
233
}
234
235
// CSS for modal transitions
236
/*
237
.modal-enter {
238
opacity: 0;
239
}
240
241
.modal-enter-active {
242
opacity: 1;
243
transition: opacity 200ms ease-in;
244
}
245
246
.modal-leave {
247
opacity: 1;
248
}
249
250
.modal-leave-active {
251
opacity: 0;
252
transition: opacity 200ms ease-out;
253
}
254
255
.modal-backdrop {
256
position: fixed;
257
top: 0;
258
left: 0;
259
right: 0;
260
bottom: 0;
261
background: rgba(0, 0, 0, 0.5);
262
display: flex;
263
align-items: center;
264
justify-content: center;
265
}
266
267
.modal-content {
268
background: white;
269
padding: 20px;
270
border-radius: 4px;
271
position: relative;
272
max-width: 500px;
273
width: 90%;
274
}
275
*/
276
```
277
278
### Route Transitions
279
280
```javascript
281
import { CSSTransitionGroup } from 'preact-compat';
282
283
class App extends Component {
284
state = { currentRoute: 'home' };
285
286
navigate = (route) => {
287
this.setState({ currentRoute: route });
288
};
289
290
renderRoute = () => {
291
const { currentRoute } = this.state;
292
293
switch (currentRoute) {
294
case 'home':
295
return <HomePage key="home" />;
296
case 'about':
297
return <AboutPage key="about" />;
298
case 'contact':
299
return <ContactPage key="contact" />;
300
default:
301
return <HomePage key="home" />;
302
}
303
};
304
305
render() {
306
return (
307
<div>
308
<nav>
309
<button onClick={() => this.navigate('home')}>Home</button>
310
<button onClick={() => this.navigate('about')}>About</button>
311
<button onClick={() => this.navigate('contact')}>Contact</button>
312
</nav>
313
314
<CSSTransitionGroup
315
transitionName="page"
316
transitionEnterTimeout={300}
317
transitionLeaveTimeout={300}
318
component="main"
319
className="page-container"
320
>
321
{this.renderRoute()}
322
</CSSTransitionGroup>
323
</div>
324
);
325
}
326
}
327
```
328
329
### Basic TransitionGroup
330
331
```javascript
332
import { TransitionGroup } from 'preact-compat';
333
334
class CustomTransitionGroup extends Component {
335
render() {
336
return (
337
<TransitionGroup component="div" className="transition-container">
338
{this.props.items.map(item => (
339
<CustomTransitionChild key={item.id} item={item} />
340
))}
341
</TransitionGroup>
342
);
343
}
344
}
345
346
// Custom child component that handles its own transitions
347
class CustomTransitionChild extends Component {
348
componentWillEnter(done) {
349
// Custom enter animation
350
const el = this.refs.element;
351
el.style.opacity = '0';
352
el.style.transform = 'translateY(-20px)';
353
354
requestAnimationFrame(() => {
355
el.style.transition = 'all 300ms ease';
356
el.style.opacity = '1';
357
el.style.transform = 'translateY(0)';
358
359
setTimeout(done, 300);
360
});
361
}
362
363
componentWillLeave(done) {
364
// Custom leave animation
365
const el = this.refs.element;
366
el.style.transition = 'all 300ms ease';
367
el.style.opacity = '0';
368
el.style.transform = 'translateY(20px)';
369
370
setTimeout(done, 300);
371
}
372
373
render() {
374
return (
375
<div ref="element">
376
{this.props.item.content}
377
</div>
378
);
379
}
380
}
381
```
382
383
## Import Patterns
384
385
```javascript
386
// Main imports
387
import { TransitionGroup, CSSTransitionGroup } from 'preact-compat';
388
389
// Library imports
390
import { TransitionGroup, CSSTransitionGroup } from 'preact-compat/lib/ReactTransitionGroup';
391
392
// CommonJS
393
const { TransitionGroup, CSSTransitionGroup } = require('preact-compat/lib/ReactTransitionGroup');
394
```
395
396
## Types
397
398
```javascript { .api }
399
interface TransitionGroupProps {
400
component?: string | ComponentType;
401
[key: string]: any;
402
}
403
404
interface CSSTransitionGroupProps {
405
transitionName: string | TransitionClasses;
406
transitionEnterTimeout: number;
407
transitionLeaveTimeout: number;
408
transitionAppear?: boolean;
409
transitionAppearTimeout?: number;
410
component?: string | ComponentType;
411
[key: string]: any;
412
}
413
414
interface TransitionClasses {
415
enter: string;
416
enterActive: string;
417
leave: string;
418
leaveActive: string;
419
appear?: string;
420
appearActive?: string;
421
}
422
423
interface TransitionChildComponent {
424
componentWillEnter?(done: () => void): void;
425
componentDidEnter?(): void;
426
componentWillLeave?(done: () => void): void;
427
componentDidLeave?(): void;
428
componentWillAppear?(done: () => void): void;
429
componentDidAppear?(): void;
430
}
431
```