Animation

Animation

Micro-interactions that feel natural. Zero dependencies.

Built-in Transitions

typescript
1import { Modal, Select, Button } from '@flint-ui/core'
2
3// Modal — fade + scale on enter, fade + scale on exit
4function Example() {
5 const [open, setOpen] = useState(false)
6
7 return (
8 <>
9 <Button onClick={() => setOpen(true)}>
10 Open Modal
11 </Button>
12
13 <Modal
14 open={open}
15 onClose={() => setOpen(false)}
16 transition="scale" // 'scale' | 'slide' | 'fade'
17 duration={200}
18 >
19 <Modal.Title>Confirm Action</Modal.Title>
20 <Modal.Body>Are you sure?</Modal.Body>
21 <Modal.Footer>
22 <Button onClick={() => setOpen(false)}>Cancel</Button>
23 <Button variant="primary">Confirm</Button>
24 </Modal.Footer>
25 </Modal>
26 </>
27 )
28}
29
30// Select — dropdown slides in with spring physics
31<Select
32 options={options}
33 transition="slide"
34 transitionDuration={150}
35/>
36
37// Button — press feedback scales to 0.97
38<Button pressScale={0.97}>
39 Click me
40</Button>

Built-in transitions for Modal, Select, and Button

Custom Animations

typescript
1import { useTransition } from '@flint-ui/core'
2
3function FadeIn({ show, children }: { show: boolean; children: React.ReactNode }) {
4 const { mounted, style } = useTransition(show, {
5 from: { opacity: 0, transform: 'translateY(8px)' },
6 enter: { opacity: 1, transform: 'translateY(0px)' },
7 exit: { opacity: 0, transform: 'translateY(-8px)' },
8 duration: 200,
9 })
10
11 if (!mounted) return null
12
13 return <div style={style}>{children}</div>
14}
15
16// Usage
17function App() {
18 const [visible, setVisible] = useState(false)
19 return (
20 <>
21 <Button onClick={() => setVisible((v) => !v)}>Toggle</Button>
22 <FadeIn show={visible}>
23 <Card>This fades in and out smoothly.</Card>
24 </FadeIn>
25 </>
26 )
27}

useTransition manages enter/exit states for any element

Reduced Motion

Flint UI respects prefers-reduced-motion automatically. All built-in animations are disabled when the user prefers reduced motion.

Important: If you add custom animations, always wrap them in a reduced motion check. Flint UI provides useReducedMotion() for this.

typescript
1import { useReducedMotion, useTransition } from '@flint-ui/core'
2
3function AnimatedPanel({ show, children }: { show: boolean; children: React.ReactNode }) {
4 const reducedMotion = useReducedMotion()
5
6 const { mounted, style } = useTransition(show, {
7 from: reducedMotion
8 ? { opacity: 0 }
9 : { opacity: 0, transform: 'scale(0.95)' },
10 enter: reducedMotion
11 ? { opacity: 1 }
12 : { opacity: 1, transform: 'scale(1)' },
13 exit: reducedMotion
14 ? { opacity: 0 }
15 : { opacity: 0, transform: 'scale(0.95)' },
16 duration: reducedMotion ? 0 : 200,
17 })
18
19 if (!mounted) return null
20 return <div style={style}>{children}</div>
21}

useReducedMotion gracefully degrades animations to opacity-only