A high-performance, type-safe SF Symbols library for React Native, built with Nitro Modules and SwiftUI.
Render native iOS SF Symbols with animation support, multiple rendering modes, and complete TypeScript autocomplete.
- π Nitro Powered β Near-zero-overhead JSI bridging for maximum performance
- π¨ Multiple Rendering Modes β Monochrome, hierarchical, palette, and multicolor
- β¨ Native Animations β Support for Discrete (one-shot), Indefinite (looping), and Transition effects
- π Symbol Variants β Fill, slash, circle, square, and rectangle variants
- π€ Typography Control β Full control over weight (9 options) and scale (3 options)
- π¨ Multi-Color Support β Use up to 3 colors with palette rendering mode
- π Flexible Color Formats β Supports named colors, hex, RGB, RGBA, and HSL color strings
- π Full TypeScript Support β Complete autocomplete for all SF Symbol names and props
- iOS 17.0+ for core functionality
- iOS 18.0+ for advanced effects (Wiggle, Rotate, Breathe)
- iOS 26.0+ for the Draw-on effect
- New Architecture enabled
IMPORTANT This library cannot be used with Expo Go due to custom native Swift code. You must use a development build.
# Install the library
npm install react-native-nitro-symbols
# Install required peer dependency
npm install react-native-nitro-modules
# For Expo projects
npx expo prebuild
# Install iOS pods
cd ios && pod install && cd ..
# Run the app
npx expo run:iosThis library works seamlessly with Uniwind, bringing Tailwind CSS utility classes to React Native.
To use Tailwind classes with SymbolView, follow the Uniwind Quickstart to set up your project.
Wrap Components (for custom components like SymbolView):
import { withUniwind } from 'uniwind';
import { SymbolView } from 'react-native-nitro-symbols';
const StyledSymbolView = withUniwind(SymbolView);Use Tailwind Classes:
<StyledSymbolView
symbolName="heart.fill"
className="w-12 h-12 text-red-500"
/>For an example of how to use Uniwind with the component, check out: UniwindDemo.tsx
For complete setup instructions, see the Uniwind Quickstart.
import { SymbolView } from 'react-native-nitro-symbols'
export default function App() {
return (
<SymbolView
symbolName="heart.fill"
tintColor="#FF3B30"
pointSize={50}
weight="bold"
/>
)
}| Prop | Type | Default | Description |
|---|---|---|---|
symbolName |
SFSymbol |
required | Name of the SF Symbol with full autocomplete support |
pointSize |
number |
24 |
Font size of the symbol in points |
weight |
SymbolWeight |
"regular" |
Symbol weight: ultralight, thin, light, regular, medium, semibold, bold, heavy, black |
scale |
SymbolScale |
"medium" |
Image scale: small, medium, large |
tintColor |
ColorValue |
undefined |
Color for monochrome rendering. Supports named colors ("red"), hex ("#FF0000"), RGB, RGBA, HSL |
colors |
ColorValue[] |
undefined |
Array of colors for palette rendering (up to 3 colors). Supports all React Native color formats |
renderingMode |
SymbolRenderingMode |
"monochrome" |
Rendering mode: monochrome, hierarchical, palette, multicolor |
variant |
SymbolVariant |
undefined |
Symbol variant: fill, slash, circle, square, rectangle |
effect |
SFSymbolEffect |
undefined |
Animation effect. See Animation Effects below. |
isAnimating |
boolean |
false |
Trigger for discrete effects (change value to trigger) or toggle for indefinite loops. |
isVisible |
boolean |
true |
Required for the appear effect to trigger exit animations correctly. |
fallback |
ReactNode |
undefined |
(Android/Web only) React node to render on non-iOS platforms (e.g. Ionicons, Text). |
<SymbolView
symbolName="star.fill"
tintColor="gold" // Named color
pointSize={60}
weight="bold"
/><SymbolView
symbolName="theatermasks"
renderingMode="palette"
colors={['purple', '#8E8E93']} // Mix named colors and hex
pointSize={60}
weight="bold"
/>Change the isAnimating prop to trigger the effect once.
import { useState } from 'react'
export function NotificationBell() {
const [trigger, setTrigger] = useState(false)
return (
<TouchableOpacity onPress={() => setTrigger(!trigger)}>
<SymbolView
symbolName="bell.badge.fill"
colors={['red', 'black']} // Named colors
renderingMode="palette"
pointSize={80}
effect="wiggle"
isAnimating={trigger}
/>
</TouchableOpacity>
)
}Set isAnimating to true to loop forever.
<SymbolView
symbolName="lungs.fill"
tintColor="rgba(50, 173, 230, 1)" // RGBA format
pointSize={80}
effect="breathe"
isAnimating={true}
/>Simply change the symbolName while effect="replace" is active.
<SymbolView
symbolName={isAuthenticated ? 'checkmark.circle.fill' : 'faceid'}
effect="replace"
tintColor={isAuthenticated ? 'green' : 'black'} // Named colors
pointSize={80}
/>WARNING Crucial: Do not unmount the component. Use
isVisibleprop and fixed dimensions. See example app for more details on usage.
<View>
{/* The symbol stays mounted to play the exit animation */}
<SymbolView
symbolName="swift"
pointSize={80}
isVisible={showIcon}
effect="appear"
/>
</View>This library maps isAnimating intelligently based on the effect type:
Change isAnimating (true -> false or false -> true) to trigger once.
| Effect | iOS Version | Description |
|---|---|---|
wiggle |
18.0+ | Wiggles the symbol side to side (e.g., for alerts) |
bounce |
17.0+ | Bounces the symbol (e.g., for notifications) |
scaleup |
18.0+ | Scales the symbol up momentarily |
scaledown |
18.0+ | Scales the symbol down momentarily |
Set isAnimating={true} to loop, {false} to stop.
| Effect | iOS Version | Description |
|---|---|---|
breathe |
18.0+ | Smoothly fades opacity in and out |
rotate |
18.0+ | Rotates the symbol continuously |
pulse |
17.0+ | Pulses the opacity (e.g., recording status) |
variablecolor |
18.0+ | Cycles opacity through layers |
Controlled by specific props.
| Effect | Prop | Description |
|---|---|---|
replace |
symbolName |
Morphs the vector paths when the name changes |
appear |
isVisible |
Scales/Fades in and out when visibility changes |
drawon |
isAnimating |
Draws the symbol path (writing effect) |
Since SF Symbols are Apple-proprietary, this library is iOS-only. However, you can use the fallback prop to gracefully handle other platforms.
The fallback prop accepts any React Node, allowing you to render alternative icons (like react-native-vector-icons or lucide-react-native) on Android and Web.
import { SymbolView } from 'react-native-nitro-symbols'
import Ionicons from '@expo/vector-icons/Ionicons'
;<SymbolView
symbolName="star.fill"
tintColor="gold"
fallback={<Ionicons name="star" size={24} color="gold" />}
/>For a complete example of how to build a cross-platform icon component, check out: FallbackDemo.tsx
This library provides full TypeScript autocomplete for all SF Symbol names. When you type symbolName=", your IDE will suggest all available symbols.
You can also browse symbols at: SF Symbols App (macOS)
This library requires custom native code. Create a development build:
npx expo prebuild
npx expo run:iosEnsure you do not have two instaces of react-native running at the same time.
- Check that you are on the supported iOS version (many effects need iOS 18).
- For
.appeartransitions, ensure you are using theisVisibleprop and not conditionally unmounting the component in React Native. - For
.appear, ensure the component has a fixed width and height style.
MIT License - see LICENSE file for details.
Made with β€οΈ by Davey Eke for the React Native community