Recorded on iPhone. A tilted wall of paintings drifts under a soft blur at the status bar and a deep frost behind the onboarding copy.
Blur
Progressive Blur
Content frosts over gradually toward any edge of the screen, with no hard line where the blur starts.
Features
- Your content fades softly into a blur at the edge of the screen, with no hard line
- Blur the top, the bottom, the sides, or all four at once
- Keep the screen sharp until someone scrolls, then let the blur build
- Blend it into your background so buttons and text stay easy to read
- Works on lists, photos, videos and web pages
- The real system blur on iPhone and Android, and smooth while you scroll
Built with
- Expo native module
- iOS: UIVisualEffectView (Swift, Objective-C)
- Android: RenderEffect (Kotlin)
- Reanimated
Installation
Usage
With nothing else set, the top 110 points blur. The same code runs on iOS and Android.
Platforms
It's a native module with its own code for each platform, so the blur is the platform's own, not a JavaScript imitation.
| iOS | Android | |
|---|---|---|
| Supported | iOS 16.4 and later | Android 12 (API 31) and later for the blur; Android 7–11 shows the content sharp, with the tint |
| Blur | UIKit's system blur (UIVisualEffectView), the one under iOS's own bars | Android's RenderEffect Gaussian blur |
| Native code | Swift and Objective-C | Kotlin |
| How the edge is built | Three system blurs of growing strength per edge, each faded in by a gradient mask (CALayer); paused animators hold each blur at part strength | Your content is recorded once per frame; each edge's strip is blurred at three strengths, each faded in by a gradient mask |
| Blur strength | Up to about 40 points, the system blur's maximum | Any maxBlur |
saturation, brightness | Not available; a fixed soft desaturation instead | Supported |
On both, the TypeScript component and Reanimated are shared: edge depths and intensity reach the native view from the UI thread, so nothing re-renders while you scroll.
Examples
Crisp until you scroll
The blur fades in over the first 180 points of scroll, so the page is sharp at rest.
A different look on each edge
Shared settings go on the component; each edge overrides only what differs.
Fading at both sides of a card
A horizontal gallery that softens into its rounded corners.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | Required | What gets blurred, usually a ScrollView or list. |
top | EdgeProp | — | Blur along the top: true, a depth in points, a shared value, or { size, tint, ...look }. The top blurs if no edge is set. |
bottom | EdgeProp | — | Blur along the bottom. Same values as top. |
left | EdgeProp | — | Blur along the left. Same values as top. |
right | EdgeProp | — | Blur along the right. Same values as top. |
intensity | number | SharedValue<number> | 1 | Scales the blur and the tint, 0–1. |
tint | ColorValue | — | A colour the edge fades into. Leave it out for a pure blur. |
preset | "default" | "soft" | "strong" | "default" | The overall look: the standard frost, a lighter blur with a gentle ramp, or a heavy blur that reaches full strength halfway across the band. |
config | Partial<ProgressiveBlurConfig> | — | Fine tuning. See Advanced. |
style | StyleProp<ViewStyle> | — | Size it like any view. |
Advanced
Everything most apps never need to touch.
Every field is optional and overrides the preset. All but cornerRadius can also be set on a single edge.
| Field | Default | Description |
|---|---|---|
maxBlur | 40 | Blur at the edge, in points. iOS tops out at about 40. |
curve | S-curve | How the blur grows across the band: "linear", "gentle", "smooth", "smoother", "sharp", "soft", or a cubic Bézier { x1, y1, x2, y2 }. |
softness | 1 | Share of the band the ramp plays over, 0.05–1. Lower values leave the outer part fully frosted. |
tintOpacity | 0.6 | How strongly tint shows at the edge, 0–1. |
saturation | 0.9 | Android only. Saturation of the blurred pixels. |
brightness | 1.03 | Android only. Brightness of the blurred pixels. |
cornerRadius | 0 | Rounds and clips the view and the blur together. |
- It blurs its own children, not whatever sits behind it. Wrap the content that should soften, usually the
ScrollView, and float headers and buttons over it as siblings. - Use
config.cornerRadiusfor rounded corners.style.borderRadiusrounds the view but not the blur. - Edge depths are in points, so a band looks the same on a phone and a tablet.
- An edge depth or
intensitycan be a Reanimated shared value; it updates on the UI thread without a re-render. - It runs on iOS 16.4+ and Android, on the New Architecture. There is no web version. See Platforms for what each one uses.
- It is native code, so rebuild the app after adding it. If the view renders but never blurs, you're on an older build.
- The blur adds nothing to the accessibility tree, and its children stay readable by screen readers as usual.
- Nothing moves on its own, so Reduce Motion changes nothing. If your app honours Reduce Transparency, pass a solid
tintwithtintOpacity: 1.
How it works
It's a local Expo native module for iOS and Android: a small TypeScript component over each platform's own blur, which is why it can soften native views that a JavaScript or Skia blur can't reach. Each blurred edge is a band that stacks three blurs of growing strength, each faded in over its own slice of the curve, so the blur radius grows toward the edge instead of one heavy blur cross-fading in. On iOS these are system blur views behind gradient masks; on Android each edge strip is blurred with RenderEffect. Edge depths and intensity travel to native as animated props, so scrolling never touches React.