Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 90 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,14 @@

# phosphor-react-native

[![npm version](https://img.shields.io/npm/v/phosphor-react-native.svg)](https://www.npmjs.com/package/phosphor-react-native)
[![npm downloads](https://img.shields.io/npm/dm/phosphor-react-native.svg)](https://www.npmjs.com/package/phosphor-react-native)
[![license](https://img.shields.io/npm/l/phosphor-react-native.svg)](LICENSE)

Phosphor is a flexible icon family for interfaces, diagrams, presentations — whatever, really. Explore all our icons at [phosphoricons.com](https://phosphoricons.com).
Inspired by [phosphor-react](https://github.com/phosphor-icons/phosphor-react).
Inspired by [@phosphor-icons/react](https://github.com/phosphor-icons/react).

This package ships 1512 icons in 6 weights, generated from [@phosphor-icons/core](https://github.com/phosphor-icons/core).

<table>
<tr>
Expand All @@ -28,9 +34,15 @@ or
npm install --save phosphor-react-native react-native-svg
```

Expo:

```bash
npx expo install phosphor-react-native react-native-svg
```

## Usage

Simply import the icons you need, and add them anywhere in your render method. Phosphor supports tree-shaking, so your bundle only includes code for the icons you use.
Import the icons you need, and add them anywhere in your render method.

```tsx
import React from 'react';
Expand All @@ -48,40 +60,71 @@ const App = () => {
};
```

### Bundle size

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](https://github.com/duongdev/phosphor-react-native/issues/61).

Two ways to avoid that:

**1. Import each icon directly** — works on every setup, no configuration:

```tsx
import { StarIcon } from 'phosphor-react-native/src/icons/Star';
```

**2. Enable Expo's experimental tree-shaking** — see [the Expo guide](https://docs.expo.dev/guides/tree-shaking/). 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.

### Typescript support
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
```ts
import type { SvgProps as DefaultSvgProps } from 'react-native-svg';
import 'react-native-svg';
import 'phosphor-react-native';

declare module 'react-native-svg' {
interface SvgProps extends DefaultSvgProps {
interface SvgProps {
className?: string;
}
}
declare module "phosphor-react-native" {
interface IconProps extends DefaultIconProps {
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`).

### Props

Icon components accept all props that you can pass to a normal SVG element, including inline `style` objects, `onClick` handlers, and more. The main way of styling them will usually be with the following props:
Icons are styled with the following props:

- **color?**: `string` – Icon stroke/fill color. Can be any CSS color string, including `hex`, `rgb`, `rgba`, `hsl`, `hsla`, named colors.
- **size?**: `number | string` – Icon height & width. As with standard React elements, this can be a number, or a string with units in `px`, `%`, `em`, `rem`, `pt`, `cm`, `mm`, `in`.
- **weight?**: `"thin" | "light" | "regular" | "bold" | "fill" | "duotone"` – Icon weight/style. 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.
- **mirrored?**: `boolean` – Flip the icon horizontally. Can be useful in RTL languages where normal icon orientation is not appropriate.
- **color?**: `string` – Icon stroke/fill color. Any color string React Native accepts, including `hex`, `rgb`, `rgba`, `hsl`, `hsla`, named colors. Default `#000`.
- **size?**: `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.
- **weight?**: `"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.
- **mirrored?**: `boolean` – Flip the icon horizontally. Default `false`. Can be useful in RTL languages where normal icon orientation is not appropriate.
- **style?**: `StyleProp<ViewStyle | Omit<TextStyle, 'cursor'>>` – Style applied to the underlying `Svg`.
- **title?**: `string` – Accessibility label
- **titleId?**: `string` – Accessibility label ID
- **testID?**: `string` – testID for tests
- **duotoneColor?**: `string` – Duotone fill color. Can be any CSS color string, including `hex`, `rgb`, `rgba`, `hsl`, `hsla`, named colors. Default value to black.
- **duotoneOpacity?**: `number` – The opacity of the duotoneColor. Default value to 0.2.
- **testID?**: `string` – testID for tests. Falls back to `phosphor-react-native-<name>-<weight>`, where `<weight>` is the weight you passed explicitly.
- **duotoneColor?**: `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.
- **duotoneOpacity?**: `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](#typescript-support) if you need more.

### Context

Expand Down Expand Up @@ -111,11 +154,13 @@ const App = () => {
};
```

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.

### Imports

You may wish to import all icons at once for use in your project, though depending on your bundler this could prevent tree-shaking and make your app's bundle larger.
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](#bundle-size).

```tsx
import * as Icon from "phosphor-react-native";
Expand All @@ -129,25 +174,42 @@ import * as Icon from "phosphor-react-native";
In cases where tree shaking does not work (resulting in large bundle size), you can import icons individually in this format:

```tsx
// Javascript
import { StarIcon } from "phosphor-react-native/lib/commonjs/icons/Star";

// Typescript
import { StarIcon } from 'phosphor-react-native/src/icons/Star';

<StarIcon size="24px" />
<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.

### Migrating from v2

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` |

## Contributing

See [CONTRIBUTING.md](CONTRIBUTING.md) for the development workflow. A runnable Expo app lives in [`example/`](example). Icons are generated from the `core` git submodule, so start with:

```bash
git submodule update --init --recursive
```

## Related Projects

- [phosphor-home](https://github.com/phosphor-icons/phosphor-home) ▲ Phosphor homepage and general info
- [phosphor-react](https://github.com/phosphor-icons/phosphor-react) ▲ Phosphor icon component library for React
- [phosphor-vue](https://github.com/phosphor-icons/phosphor-vue) ▲ Phosphor icon component library for Vue
- [phosphor-icons](https://github.com/phosphor-icons/phosphor-icons) ▲ Phosphor icons for Vanilla JS
- [phosphor-flutter](https://github.com/phosphor-icons/phosphor-flutter) ▲ Phosphor IconData library for Flutter
- [phosphor-webcomponents](https://github.com/phosphor-icons/phosphor-webcomponents) ▲ Phosphor icons as Web Components
- [phosphor-figma](https://github.com/phosphor-icons/phosphor-figma) ▲ Phosphor icons Figma plugin
- [phosphor-sketch](https://github.com/phosphor-icons/phosphor-sketch) ▲ Phosphor icons Sketch plugin
- [homepage](https://github.com/phosphor-icons/homepage) ▲ Phosphor homepage and general info
- [core](https://github.com/phosphor-icons/core) ▲ Phosphor icon assets, the source this package generates from
- [react](https://github.com/phosphor-icons/react) ▲ Phosphor icon component library for React
- [vue](https://github.com/phosphor-icons/vue) ▲ Phosphor icon component library for Vue
- [web](https://github.com/phosphor-icons/web) ▲ Phosphor icons for Vanilla JS
- [flutter](https://github.com/phosphor-icons/flutter) ▲ Phosphor IconData library for Flutter
- [webcomponents](https://github.com/phosphor-icons/webcomponents) ▲ Phosphor icons as Web Components
- [figma](https://github.com/phosphor-icons/figma) ▲ Phosphor icons Figma plugin
- [sketch](https://github.com/phosphor-icons/sketch) ▲ Phosphor icons Sketch plugin

## License

Expand Down
4 changes: 2 additions & 2 deletions global.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { SvgProps as DefaultSvgProps } from 'react-native-svg';
import 'react-native-svg';

declare module 'react-native-svg' {
interface SvgProps extends DefaultSvgProps {
interface SvgProps {
className?: string;
}
}
Loading