phosphor-icons for react-native. A flexible icon family for React Native
See the code
Phosphor is a flexible icon family for interfaces, diagrams, presentations — whatever, really. Explore all our icons at phosphoricons.com. Inspired by @phosphor-icons/react.
This package ships 1512 icons in 6 weights, generated from @phosphor-icons/core.
|
|
|
|
|
|
yarn add phosphor-react-native react-native-svg
or
npm install --save phosphor-react-native react-native-svg
Expo:
npx expo install phosphor-react-native react-native-svg
Import the icons you need, and add them anywhere in your render method.
import React from 'react';
import { View } from 'react-native';
import { HorseIcon, HeartIcon, CubeIcon } from 'phosphor-react-native';
const App = () => {
return (
<View>
<HorseIcon />
<HeartIcon color="#AE2983" weight="fill" size={32} />
<CubeIcon color="teal" weight="duotone" />
</View>
);
};
Metro does not tree-shake by default, so the import above pulls all 1512 icons into your bundle even if you use three of them. See #61.
Two ways to avoid that:
1. Import each icon directly — works on every setup, no configuration:
import { StarIcon } from 'phosphor-react-native/src/icons/Star';
2. Enable Expo's experimental tree-shaking — see the Expo guide. Then the barrel import is just as small.
Measured with yarn bundle-bench (real Metro, iOS, minified, v3.0.5):
| Scenario | Bundle | vs baseline |
|---|---|---|
| Barrel import, 1 icon, no tree-shaking | 8597 kB | +182% |
| Barrel import, 3 icons, no tree-shaking | 8598 kB | +182% |
| Direct import, 1 icon, no tree-shaking | 1876 kB | +10% |
| Barrel import, 1 icon, tree-shaking on | 1854 kB | +10% |
Icons are generated per icon, not per weight, so a single icon always carries all 6 weights.
If you get this error...
Property 'className' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes<Svg> & Pick<Readonly<SvgProps>, "children" | "style" | ... 144 more ... | "fontVariationSettings"> & InexactPartial<...> & InexactPartial<...>'
Add this code to your global.d.ts file
import 'react-native-svg';
import 'phosphor-react-native';
declare module 'react-native-svg' {
interface SvgProps {
className?: string;
}
}
declare module 'phosphor-react-native' {
interface IconProps {
className?: string;
}
}
Module augmentation merges into the existing interface, so declare only the extra members — writing interface SvgProps extends DefaultSvgProps makes the type reference itself (TS2310).
Icons are styled with the following props:
string – Icon stroke/fill color. Any color string React Native accepts, including hex, rgb, rgba, hsl, hsla, named colors. Default #000.number | string – Icon height & width. Default 24. Use a number, or a percentage string such as "50%". Other unit suffixes are parsed with parseInt, so "24px" is 24 — but "2rem" is also 2, not 32."thin" | "light" | "regular" | "bold" | "fill" | "duotone" – Icon weight/style. Default regular. Can also be used, for example, to "toggle" an icon's state: a rating component could use Stars with weight="regular" to denote an empty star, and weight="fill" to denote a filled star.boolean – Flip the icon horizontally. Default false. Can be useful in RTL languages where normal icon orientation is not appropriate.StyleProp<ViewStyle | Omit<TextStyle, 'cursor'>> – Style applied to the underlying Svg.string – Accessibility labelstring – Accessibility label IDstring – testID for tests. Falls back to phosphor-react-native-<name>-<weight>, where <weight> is the weight you passed explicitly.string – Fill color of the duotone background layer. Defaults to color, so an icon with color="teal" gets a teal background layer — not a black one.number – The opacity of the duotoneColor. Default 0.2.IconProps is a closed type: props outside this list (onPress, fill, …) are forwarded to the underlying Svg at runtime, but TypeScript rejects them. Widen IconProps with module augmentation if you need more.
Phosphor takes advantage of React Context to make applying a default style to all icons simple. Create an IconContext.Provider at the root of the app (or anywhere above the icons in the tree) and pass in a configuration object with props to be applied by default to all icons:
import React from 'react';
import { View } from 'react-native';
import { IconContext, HorseIcon, HeartIcon, CubeIcon } from 'phosphor-react-native';
const App = () => {
return (
<IconContext.Provider
value={{
color: 'limegreen',
size: 32,
weight: 'bold',
}}
>
<View>
<HorseIcon /> {/* I'm lime-green, 32px, and bold! */}
<HeartIcon /> {/* Me too! */}
<CubeIcon /> {/* Me three :) */}
</View>
</IconContext.Provider>
);
};
Every styling prop is context-able: color, size, weight, mirrored, style, duotoneColor and duotoneOpacity. Props set on an icon win over the Context. Defaults when neither is set: color: '#000', size: 24, weight: 'regular', mirrored: false, duotoneOpacity: 0.2.
You may create multiple Contexts for styling icons differently in separate regions of an application; icons use the nearest Context above them to determine their style.
You may wish to import all icons at once for use in your project. Without tree-shaking this pulls every icon into your bundle — see Bundle size.
import * as Icon from "phosphor-react-native";
...
<Icon.SmileyIcon />
<Icon.FolderIcon weight="thin" />
<Icon.BatteryHalfIcon size="24px" />
<Icon.AirplaneTakeoffIcon size="24px" mirrored={true} />
In cases where tree shaking does not work (resulting in large bundle size), you can import icons individually in this format:
import { StarIcon } from 'phosphor-react-native/src/icons/Star';
<StarIcon size={24} />
The file name is the icon name in PascalCase (arrow-left → ArrowLeft), and the export is that name suffixed with Icon. src/icons/* is the only subpath this package exports — importing from lib/commonjs/... fails with ERR_PACKAGE_PATH_NOT_EXPORTED on any bundler that honours exports, which Metro does by default since React Native 0.79.
Since v3 every icon is exported with an Icon suffix: Horse → HorseIcon. The old names still work but are marked @deprecated, except for three whose bare names collide with other identifiers and were removed outright:
| v2 | v3 |
|---|---|
Circle | CircleIcon |
Path | PathIcon |
Infinity | InfinityIcon |
See CONTRIBUTING.md for the development workflow. A runnable Expo app lives in example/. Icons are generated from the core git submodule, so start with:
git submodule update --init --recursive
MIT
556 followers · starred Dec 2023
104 followers · starred Dec 2025
203 followers · starred Aug 2024
phosphor-icons for react-native. A flexible icon family for React Native
See the code
Phosphor is a flexible icon family for interfaces, diagrams, presentations — whatever, really. Explore all our icons at phosphoricons.com. Inspired by @phosphor-icons/react.
This package ships 1512 icons in 6 weights, generated from @phosphor-icons/core.
|
|
|
|
|
|
yarn add phosphor-react-native react-native-svg
or
npm install --save phosphor-react-native react-native-svg
Expo:
npx expo install phosphor-react-native react-native-svg
Import the icons you need, and add them anywhere in your render method.
import React from 'react';
import { View } from 'react-native';
import { HorseIcon, HeartIcon, CubeIcon } from 'phosphor-react-native';
const App = () => {
return (
<View>
<HorseIcon />
<HeartIcon color="#AE2983" weight="fill" size={32} />
<CubeIcon color="teal" weight="duotone" />
</View>
);
};
Metro does not tree-shake by default, so the import above pulls all 1512 icons into your bundle even if you use three of them. See #61.
Two ways to avoid that:
1. Import each icon directly — works on every setup, no configuration:
import { StarIcon } from 'phosphor-react-native/src/icons/Star';
2. Enable Expo's experimental tree-shaking — see the Expo guide. Then the barrel import is just as small.
Measured with yarn bundle-bench (real Metro, iOS, minified, v3.0.5):
| Scenario | Bundle | vs baseline |
|---|---|---|
| Barrel import, 1 icon, no tree-shaking | 8597 kB | +182% |
| Barrel import, 3 icons, no tree-shaking | 8598 kB | +182% |
| Direct import, 1 icon, no tree-shaking | 1876 kB | +10% |
| Barrel import, 1 icon, tree-shaking on | 1854 kB | +10% |
Icons are generated per icon, not per weight, so a single icon always carries all 6 weights.
If you get this error...
Property 'className' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes<Svg> & Pick<Readonly<SvgProps>, "children" | "style" | ... 144 more ... | "fontVariationSettings"> & InexactPartial<...> & InexactPartial<...>'
Add this code to your global.d.ts file
import 'react-native-svg';
import 'phosphor-react-native';
declare module 'react-native-svg' {
interface SvgProps {
className?: string;
}
}
declare module 'phosphor-react-native' {
interface IconProps {
className?: string;
}
}
Module augmentation merges into the existing interface, so declare only the extra members — writing interface SvgProps extends DefaultSvgProps makes the type reference itself (TS2310).
Icons are styled with the following props:
string – Icon stroke/fill color. Any color string React Native accepts, including hex, rgb, rgba, hsl, hsla, named colors. Default #000.number | string – Icon height & width. Default 24. Use a number, or a percentage string such as "50%". Other unit suffixes are parsed with parseInt, so "24px" is 24 — but "2rem" is also 2, not 32."thin" | "light" | "regular" | "bold" | "fill" | "duotone" – Icon weight/style. Default regular. Can also be used, for example, to "toggle" an icon's state: a rating component could use Stars with weight="regular" to denote an empty star, and weight="fill" to denote a filled star.boolean – Flip the icon horizontally. Default false. Can be useful in RTL languages where normal icon orientation is not appropriate.StyleProp<ViewStyle | Omit<TextStyle, 'cursor'>> – Style applied to the underlying Svg.string – Accessibility labelstring – Accessibility label IDstring – testID for tests. Falls back to phosphor-react-native-<name>-<weight>, where <weight> is the weight you passed explicitly.string – Fill color of the duotone background layer. Defaults to color, so an icon with color="teal" gets a teal background layer — not a black one.number – The opacity of the duotoneColor. Default 0.2.IconProps is a closed type: props outside this list (onPress, fill, …) are forwarded to the underlying Svg at runtime, but TypeScript rejects them. Widen IconProps with module augmentation if you need more.
Phosphor takes advantage of React Context to make applying a default style to all icons simple. Create an IconContext.Provider at the root of the app (or anywhere above the icons in the tree) and pass in a configuration object with props to be applied by default to all icons:
import React from 'react';
import { View } from 'react-native';
import { IconContext, HorseIcon, HeartIcon, CubeIcon } from 'phosphor-react-native';
const App = () => {
return (
<IconContext.Provider
value={{
color: 'limegreen',
size: 32,
weight: 'bold',
}}
>
<View>
<HorseIcon /> {/* I'm lime-green, 32px, and bold! */}
<HeartIcon /> {/* Me too! */}
<CubeIcon /> {/* Me three :) */}
</View>
</IconContext.Provider>
);
};
Every styling prop is context-able: color, size, weight, mirrored, style, duotoneColor and duotoneOpacity. Props set on an icon win over the Context. Defaults when neither is set: color: '#000', size: 24, weight: 'regular', mirrored: false, duotoneOpacity: 0.2.
You may create multiple Contexts for styling icons differently in separate regions of an application; icons use the nearest Context above them to determine their style.
You may wish to import all icons at once for use in your project. Without tree-shaking this pulls every icon into your bundle — see Bundle size.
import * as Icon from "phosphor-react-native";
...
<Icon.SmileyIcon />
<Icon.FolderIcon weight="thin" />
<Icon.BatteryHalfIcon size="24px" />
<Icon.AirplaneTakeoffIcon size="24px" mirrored={true} />
In cases where tree shaking does not work (resulting in large bundle size), you can import icons individually in this format:
import { StarIcon } from 'phosphor-react-native/src/icons/Star';
<StarIcon size={24} />
The file name is the icon name in PascalCase (arrow-left → ArrowLeft), and the export is that name suffixed with Icon. src/icons/* is the only subpath this package exports — importing from lib/commonjs/... fails with ERR_PACKAGE_PATH_NOT_EXPORTED on any bundler that honours exports, which Metro does by default since React Native 0.79.
Since v3 every icon is exported with an Icon suffix: Horse → HorseIcon. The old names still work but are marked @deprecated, except for three whose bare names collide with other identifiers and were removed outright:
| v2 | v3 |
|---|---|
Circle | CircleIcon |
Path | PathIcon |
Infinity | InfinityIcon |
See CONTRIBUTING.md for the development workflow. A runnable Expo app lives in example/. Icons are generated from the core git submodule, so start with:
git submodule update --init --recursive
MIT
556 followers · starred Dec 2023
104 followers · starred Dec 2025
203 followers · starred Aug 2024