React Native spoilers.
Hide messages, values, images, or custom views with native particle animations on iOS and Android. Supports controlled state, accessibility, and reduced motion.
Built for real content
The spoiler effect sits above native sibling content instead of flattening it into a canvas snapshot. Hide a message, a few words, an account number, an image, or an entire custom view.
- Touch-origin revealA circular reveal begins exactly where the user taps.
- Ambient motionThree particle depth and opacity tiers move independently.
- Controlled or localOwn reveal state in the parent or let the component manage it.
- Safe descendantsHidden content is blocked from touch and accessibility focus.
- Reduced MotionSystem animation preferences are respected on both platforms.
- Runtime limitsUnsafe configuration is normalized and particle work stays bounded.
Install
Package and native peers
npm install react-native-spoiler-view \
react-native-reanimated \
react-native-gesture-handlerFor Reanimated 4, also install react-native-worklets and put its Babel plugin last.
npm install react-native-workletsmodule.exports = {
presets: ['module:@react-native/babel-preset'],
plugins: ['react-native-worklets/plugin'],
};Choose peer dependency versions compatible with your React Native version. Reanimated 4 requires the New Architecture; Reanimated 3 remains the supported legacy lane.
Compatibility
| Lane | React Native | React | Reanimated | Gesture Handler |
|---|---|---|---|---|
| Legacy | 0.73.x | 18.x | 3.15.5 | 2.18.x |
| Current | 0.86.x | 19.x | 4.5.x + Worklets 0.10.x | 3.x |
Use it
Uncontrolled
import { Text } from 'react-native';
import { SpoilerView } from 'react-native-spoiler-view';
<SpoilerView accessibilityRevealLabel="Hidden message">
<Text>This is a secret message.</Text>
</SpoilerView>The component owns its state. Tapping toggles between hidden and revealed.
Controlled
const [revealed, setRevealed] = useState(false);
<SpoilerView
revealed={revealed}
onReveal={() => setRevealed(true)}
onHide={() => setRevealed(false)}
accessibilityRevealLabel="Hidden account number"
>
<Text>1234 5678 9012 3456</Text>
</SpoilerView>Callbacks request the change; the component animates only when the controlled prop changes.
Custom particles
<SpoilerView
config={{
particleCount: 300,
particleColor: 'rgba(255, 100, 100, 1)',
particleSizeRange: [0.5, 1.5],
revealDuration: 400,
}}
>
<Image source={secretImage} />
</SpoilerView>API
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | required | Content hidden by the spoiler |
revealed | boolean | uncontrolled | Parent-owned reveal state |
enabled | boolean | true | Enables reveal and hide gestures |
onReveal | () => void | — | Reveal request callback |
onHide | () => void | — | Hide request callback |
config | Partial<SpoilerConfig> | — | Particle and animation overrides |
style | StyleProp<ViewStyle> | — | Container style |
Default particle configuration
{
particleCount: 180,
particleDensity: 0.055,
particleSizeRange: [0.45, 0.8],
particleColor: 'rgba(80, 80, 80, 1)',
overlayColor: 'transparent',
noiseSpeed: 0.3,
driftAmount: 1,
revealDuration: 500,
}Particle count is capped at 1,000. Providing particleCount without particleDensity opts into a fixed target; otherwise density adapts the effect to the spoiler area.
Read the complete API and accessibility reference on GitHub →