A React component that simulates the classic split-flap display effect, inspired by train stations and airport displays.
- Realistic Flip Animation - Simulates authentic mechanical flipping effects
- Multiple Themes - Built-in light and dark themes
- Various Sizes - From small to extra-large size options
- Highly Customizable - Support for custom character sets, animation speed, etc.
- TypeScript Support - Complete type definitions
- LongFlap Component - Support for complex ReactNode content with ID-based switching
npm install react-split-flap
# or
yarn add react-split-flap
import React from 'react'
import { SplitFlap, Presets } from 'react-split-flap'
function App() {
return <SplitFlap value="HELLO" chars={Presets.ALPHANUM} length={5} />
}
Perfect for displaying strings with character-by-character flipping animation.
Property | Type | Default | Description |
---|---|---|---|
value |
string |
- | Value to display |
length |
number |
- | Number of digits to display. If set to 1, will display full value on one flap |
chars |
string[] |
Presets.NUM |
Available character set |
padChar |
string |
' ' |
Padding character |
padMode |
'auto' | 'start' | 'end' |
'auto' |
'auto' will align number right and string left |
digitWidth |
number |
- | Custom width for each digit (pixels) |
timing |
number |
30 |
Animation interval (milliseconds) |
hinge |
boolean |
true |
Whether to show hinge line |
theme |
'default' | 'light' | 'dark' |
'default' |
Theme variant |
size |
'small' | 'medium' | 'large' | 'xlarge' |
'medium' |
Size variant |
className |
string |
'' |
CSS class name |
style |
React.CSSProperties |
- | Inline styles |
background |
string |
- | Custom background color or gradient for the flaps |
fontColor |
string |
- | Custom font color for the flap text |
render |
(children: ReactNode) => ReactNode |
- | Custom render function |
Perfect for displaying complex ReactNode components with ID-based switching, ideal for icons, styled content, and rich components.
Property | Type | Default | Description |
---|---|---|---|
flaps |
Array<{id: string | number, component: ReactNode}> |
- | Array of flap items with ID and component |
displayId |
string | number |
- | Current display ID to show |
digitWidth |
number |
- | Custom width for the flap (pixels) |
digitHeight |
number |
- | Custom height for the flap (pixels) |
timing |
number |
60 |
Animation timing (milliseconds) |
hinge |
boolean |
true |
Whether to show hinge line |
theme |
'default' | 'light' | 'dark' |
'default' |
Theme variant |
size |
'small' | 'medium' | 'large' | 'xlarge' |
'medium' |
Size variant |
className |
string |
'' |
CSS class name |
style |
React.CSSProperties |
- | Inline styles |
background |
string |
- | Custom background color or gradient for the flaps |
fontColor |
string |
- | Custom font color for the flap text |
render |
(children: ReactNode) => ReactNode |
- | Custom render function |
- Use SplitFlap when displaying strings or simple text with character-by-character flipping
- Use LongFlap when you need:
- Complex ReactNode components (icons + text, styled content, etc.)
- ID-based switching between predefined states
- Single flap displaying rich content
- Custom rendering of complex elements
small
- 20pxmedium
- 36px (default)large
- 54pxxlarge
- 84px
default
- Default stylinglight
- Light themedark
- Dark theme
import React, { useState } from 'react'
import { SplitFlap, Presets } from 'react-split-flap'
function Counter() {
const [count, setCount] = useState(0)
return (
<div>
<SplitFlap value={count.toString()} chars={Presets.NUM} length={3} className="medium light" padMode="start" />
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
)
}
import React, { useState, useEffect } from 'react'
import { SplitFlap, Presets } from 'react-split-flap'
function TextCarousel() {
const words = ['HELLO', 'WORLD', 'REACT']
const [currentWord, setCurrentWord] = useState(words[0])
useEffect(() => {
let index = 0
const interval = setInterval(() => {
index = (index + 1) % words.length
setCurrentWord(words[index])
}, 2000)
return () => clearInterval(interval)
}, [])
return <SplitFlap value={currentWord} chars={Presets.ALPHANUM} length={5} className="large dark" timing={20} />
}
import React from 'react'
import { SplitFlap, Presets } from 'react-split-flap'
function CustomStyledFlap() {
return (
<SplitFlap
value="CUSTOM"
chars={Presets.ALPHANUM}
length={6}
size="large"
background="linear-gradient(45deg, #ff6b6b, #4ecdc4)"
fontColor="#ffffff"
timing={50}
/>
)
}
import React, { useState } from 'react'
import { LongFlap } from 'react-split-flap'
/* Keep prop "flaps" constant. Will trigger <LongFlap /> re-render when changed. */
const weatherFlaps = [
{
id: 'sunny',
component: (
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
<span>βοΈ</span>
<span>Sunny</span>
</div>
),
},
{
id: 'rainy',
component: (
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
<span>π§οΈ</span>
<span>Rainy</span>
</div>
),
},
]
function WeatherDisplay() {
const [currentWeather, setCurrentWeather] = useState('sunny')
return <LongFlap flaps={weatherFlaps} displayId={currentWeather} digitWidth={200} size="large" theme="dark" />
}
import React from 'react'
import { LongFlap } from 'react-split-flap'
const styledFlaps = [
{
id: 'status1',
component: <div style={{ fontSize: '24px', fontWeight: 'bold' }}>π READY</div>,
},
{
id: 'status2',
component: <div style={{ fontSize: '24px', fontWeight: 'bold' }}>β‘ ACTIVE</div>,
},
]
function CustomStyledLongFlap() {
const [status, setStatus] = useState('status1')
return (
<LongFlap
flaps={styledFlaps}
displayId={status}
digitWidth={250}
digitHeight={80}
background="linear-gradient(135deg, #667eea 0%, #764ba2 100%)"
fontColor="#ffffff"
timing={100}
size="xlarge"
/>
)
}
# Clone the project
git clone <repository-url>
cd react-split-flap
# Install dependencies
yarn install
# Build the package
yarn global add yalc
yarn dev:publish #use yalc to public local
# Start demo
cd demo
yarn install
yarn dev:hot #force vite use fresh package
yarn build
MIT License
Issues and Pull Requests are welcome!