Skip to content

mCodex/react-native-nitro-sfsymbols

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

41 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

react-native-nitro-sfsymbols ✨

🍎 Render Apple SF Symbols natively in React Native via Nitro Modules. Type-safe, accessible, tree-shakable.

npm npm downloads License: MIT TypeScript Nitro Modules PRs welcome


πŸ“š Table of Contents


✨ Highlights

  • 🎯 Native rendering through UIImage(systemName:) β€” no bridge overhead.
  • 🎨 All four rendering modes: monochrome, hierarchical, palette, multicolor.
  • πŸ’« iOS 17+ symbol effects: bounce, pulse, scale, rotate, appear, disappear, replace, variableColor.
  • πŸš€ Per-instance image cache keeps list scrolling allocation-free.
  • 🌳 Tree-shakable: the icon catalog is opt-in via a subpath export β€” the core ships at ~1.5 KB.
  • β™Ώ WCAG 2.2 AA-friendly: decorative-by-default, Dynamic Type support, Reduce Motion respected, Increase Contrast aware.
  • πŸ›‘οΈ Strict TypeScript 6: literal-union types, as const constants, full IDE autocomplete.
Platform Support Minimum
🍎 iOS full 16.0
πŸ’» macOS / πŸ“Ί tvOS / πŸ₯½ visionOS full latest
πŸ€– Android empty placeholder (logs a single warning) β€”

πŸ“¦ Install

yarn add react-native-nitro-sfsymbols react-native-nitro-modules
cd ios && pod install

ℹ️ react-native-nitro-modules >= 0.35 is required.


πŸš€ Usage

import { SFSymbolView, SFSymbolWeight } from 'react-native-nitro-sfsymbols';

export function FavoriteButton({ active }: { active: boolean }) {
  return (
    <SFSymbolView
      name={active ? 'heart.fill' : 'heart'}
      size={28}
      weight={SFSymbolWeight.SEMIBOLD}
      tintColor={active ? '#FF3B30' : '#8E8E93'}
      animation={active ? { type: 'bounce' } : undefined}
      accessibilityLabel={active ? 'Remove favorite' : 'Add favorite'}
      accessibilityRole="button"
    />
  );
}

πŸ“‚ Optional curated catalog

For autocomplete on the most-used symbols, import from the /icons subpath:

import { SFIcons } from 'react-native-nitro-sfsymbols/icons';

<SFSymbolView name={SFIcons.HEART_FILL} />;

The catalog is opt-in β€” consumers who pass arbitrary strings pay zero catalog cost in their bundle.

🎨 Hierarchical / palette colors

<SFSymbolView
  name="cloud.sun.fill"
  renderingMode="hierarchical"
  hierarchical={{ primary: '#FFB300' }}
/>

<SFSymbolView
  name="cloud.bolt.rain.fill"
  renderingMode="palette"
  palette={{ primary: '#2196F3', secondary: '#FFB300', tertiary: '#90CAF9' }}
/>

πŸ’« Animations (iOS 17+)

<SFSymbolView name="bell.fill" animation={{ type: 'bounce', repeating: false }} />

🧘 Animations are silently skipped when Reduce Motion is enabled (WCAG 2.3.3).


β™Ώ Accessibility

SFSymbolView is decorative by default β€” without an accessibilityLabel it's hidden from VoiceOver and TalkBack (WCAG 1.1.1 Non-text Content). Pass either of:

  • accessibilityLabel="Add to favorites" β€” explicit label.
  • accessibilityAutoLabel β€” derive a label from the symbol name ("heart.fill" β†’ "Heart").

For icon-only pressables, spread minTouchTargetStyle onto the wrapping Pressable to meet Apple HIG / WCAG 2.5.8 (minimum 44Γ—44 hit area):

import { Pressable } from 'react-native';
import { SFSymbolView, minTouchTargetStyle } from 'react-native-nitro-sfsymbols';

<Pressable style={minTouchTargetStyle} onPress={onTap}>
  <SFSymbolView name="ellipsis" accessibilityLabel="More options" accessibilityRole="button" />
</Pressable>;

size honors the user's Dynamic Type setting by default (capped at 2Γ— via maxFontSizeMultiplier). When the user enables Increase Contrast, an omitted tintColor falls back to the system label color for guaranteed contrast.


πŸ“– API

Prop Type Default
name string (or SFIcon from /icons) required
fallbackName string undefined
size number 24
weight SFSymbolWeight 'regular'
scale SFSymbolScale 'medium'
tintColor string (hex #RRGGBB / #RGB / #RRGGBBAA) system label
renderingMode SFSymbolRenderingMode 'monochrome'
hierarchical { primary; secondary?; tertiary? } β€”
palette { primary; secondary?; tertiary? } β€”
animation { type; repeating? } β€”
opacity number (0–1) 1
allowFontScaling boolean true
maxFontSizeMultiplier number 2
accessibilityAutoLabel boolean false

Standard accessibilityLabel, accessibilityHint, accessibilityRole, testID, style, etc. are forwarded.


⏫ Migrating from 1.x

  1. Bump react-native-nitro-modules to >= 0.35.
  2. Imports: SFIcons moved to a subpath:
    - import { SFIcons } from 'react-native-nitro-sfsymbols';
    + import { SFIcons } from 'react-native-nitro-sfsymbols/icons';
  3. Removed runtime helpers (use the constants directly):
    • isValidSFIcon, getAllSFIcons, camelCaseToSFSymbol, searchSFIcon
    • isValidColor, normalizeColor, clampOpacity, validateConfig, applyDefaults, optimizeProps, createHierarchicalConfig, createPaletteConfig, dimensionToSymbolSize, getPresetSize
  4. Constants are now plain objects (no longer enums). Member access is identical (SFSymbolWeight.BOLD); the type is a string-literal union.
  5. Color config keys: primaryColor β†’ primary, secondaryColor β†’ secondary, etc.
    - hierarchical={{ primaryColor: '#FF5722' }}
    + hierarchical={{ primary: '#FF5722' }}
  6. SFSymbolTheme was a duplicate of SFSymbolRenderingMode β€” removed. Use SFSymbolRenderingMode.
  7. tintColor is now string (hex). Pass '#RRGGBB', '#RGB', or '#RRGGBBAA'. Numeric/processColor values were silently dropped before β€” switching to a string keeps the type honest.
  8. variableColor boolean prop removed. Use animation={{ type: 'variableColor' }} instead, which is the actual iOS 17+ symbol effect.
  9. The icon catalog is now curated. Some 1.x entries were removed or renamed (e.g. TOGGLE_POWER β†’ POWER). If TypeScript reports an unknown member, look up the symbol on Apple's SF Symbols app and pass its name as a plain string β€” every prop accepts arbitrary strings, so missing catalog entries are never blocking.
  10. iOS 16+ minimum.

The full release notes live in CHANGELOG.md.


⚑ Performance notes

  • 🧠 The native side caches resolved UIImage instances per configuration with an 8 MB NSCache. Repeated re-renders with identical props are zero-allocation.
  • πŸ” Property updates within a single React commit are coalesced into one render pass via the run loop.
  • 🎨 The hex color parser keeps a 32-entry LRU cache.
  • πŸ“¦ The catalog is shipped behind a subpath export β€” only consumers that import 'react-native-nitro-sfsymbols/icons' pay for it.

🀝 Contributing

Contributions are very welcome! Please read CONTRIBUTING.md for the development workflow, and our Code of Conduct to keep the project a safe and inclusive space.

Quick start:

git clone https://github.com/mCodex/react-native-nitro-sfsymbols.git
cd react-native-nitro-sfsymbols
yarn
yarn typecheck && yarn lint && yarn test

To run the example app:

cd example && yarn ios

πŸ’¬ Support


πŸ™ Acknowledgments


πŸ“„ License

MIT Β© Mateus Andrade

About

🍎 Render Apple's beautiful SF Symbols natively on iOS with React Native. Zero-bridge overhead, fully typed, production-ready.

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Sponsor this project

 

Contributors