npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@matiks/rn-stroke-text

v0.3.2

Published

rn-stroke-text

Readme

@matiks/rn-stroke-text

Stroked (outlined) text for React Native, with two interchangeable renderers: a Nitro native view and a React Native Skia renderer.

Installation

yarn add @matiks/rn-stroke-text

Peer dependencies:

| Package | Required | | --- | --- | | react-native-nitro-modules | Yes | | @shopify/react-native-skia | Yes, 2.9.1 — keep in step with the Matiks client | | react / react-native | Yes |

The Skia renderer is always bundled, so Skia must be installed even if you only use mode="native".

iOS needs a pod install after adding the package. Android autolinks.

Usage

import StrokeText from '@matiks/rn-stroke-text';

<StrokeText
  text="42"
  fontSize={48}
  fontFamily="Montserrat-700"
  color="#FFFFFF"
  strokeColor="#000000"
  strokeWidth={6}
  align="center"
/>;

Props

| Prop | Type | Default | Notes | | --- | --- | --- | --- | | text | string | — | Required. Coerced with String(text). | | fontSize | number | 14 | | | fontFamily | string | platform default | See Fonts. | | color | string | #000000 | Fill colour. | | strokeColor | string | #FFFFFF | Outline colour. | | strokeWidth | number | 0 (Skia + iOS), 1dp (Android native) | | | align | 'left' \| 'center' \| 'right' | 'left' | Matches RN <Text>. Android uses ALIGN_NORMAL, so it follows RTL. | | width | number | unset | Fixed width. When unset the view sizes to the text. | | numberOfLines | number | unset | Maximum lines. | | ellipsis | boolean | false | Truncates with …. | | letterSpacing | number | unset | Skia mode only. The Nitro view has no equivalent and ignores it. | | lineHeight | number | unset | Skia mode only. Applied as a height multiplier of lineHeight / fontSize. | | fontProvider | SkTypefaceFontProvider | unset | Skia mode only. Typefaces to match against, on top of the platform font manager. Required for app-bundled fonts on Android — see Fonts. | | styles | StyleProp<ViewStyle> | — | Applied to the wrapper view. | | mode | 'native' \| 'skia' | 'native' | Renderer to use. | | accessibilityLabel | string | text | Read by screen readers. Both renderers expose the view as an accessible text element. |

Render modes

mode selects the renderer per instance. It defaults to 'native'.

native (default)

A Nitro HybridView backed by UILabel on iOS and a custom View drawing into android.graphics.Canvas on Android.

The view starts at 0×0 and measures itself after mount through the hybrid ref, so its size arrives one render after the text does. It exposes measureDimensions() natively.

skia

Builds a Skia paragraph, records it into a Picture, and draws it in a Canvas. When strokeWidth > 0 it strokes every line's outline path, then paints the paragraph on top, so the outline sits behind the glyphs. Colour glyphs such as emoji have no outline path, so when the text contains any, a dilated copy of the painted text outlines them. With no stroke it paints the paragraph directly.

Size is computed synchronously during render: the width is width when given, otherwise the longest line plus strokeWidth; the height is the paragraph height plus strokeWidth.

Choose skia when you want the text composited on the GPU alongside other Skia content, or to avoid the native view's two-pass measurement. Choose native for platform text behaviour and font handling.

Fonts

fontFamily is parsed into a family, a weight and an italic flag by splitting on -: the first segment is the family, a numeric segment becomes the weight, and italic sets the slant.

| Input | Family | Weight | Italic | | --- | --- | --- | --- | | Montserrat-700 | Montserrat | 700 | no | | Montserrat-italic-800 | Montserrat | 800 | yes | | BebasNeue-Regular | BebasNeue | 400 | no |

Skia mode resolves fonts only through the platform font manager, and matches on the font's real family name. It registers no typefaces of its own and is not given a typeface provider, so fonts that React Native or expo-font registered under an alias are not guaranteed to resolve.

| Platform | Font manager | Sees app-registered fonts | | --- | --- | --- | | Android | SkFontMgr_New_Android(nullptr, …) | No — system fonts only | | iOS | SkFontMgr_New_CoreText(nullptr) | Yes, for fonts registered process-wide |

Candidates include a spaced form of the alias, so BebasNeue-Regular is tried as BebasNeue-Regular, BebasNeue, Bebas Neue and Bebas Neue-Regular. That covers the common case where the app alias is camel-case and the font's real family name is spaced.

Native mode does not have this limitation: Android loads from assets/fonts or the React font manager, and iOS resolves through UIFont.

Bundled fonts in Skia mode

On Android the system font manager cannot see app-bundled fonts at all, whatever they are called, so name matching alone is not enough. Pass fontProvider:

import { useFonts } from '@shopify/react-native-skia';

const fontProvider = useFonts({
  'BebasNeue-Regular': [require('./assets/fonts/BebasNeue-Regular.ttf')],
  'Montserrat-700': [require('./assets/fonts/Montserrat-Bold.ttf')],
});

<StrokeText text="42" fontFamily="BebasNeue-Regular" fontProvider={fontProvider ?? undefined} />;

Register each typeface under the exact fontFamily string the call sites pass. useFonts registers by map key, so an alias key matches verbatim and neither the real family name nor the weight suffix has to line up. Build the provider once near the root of the app and share it — it loads asynchronously and returns null until ready, during which text falls back to a system font.

Known limitations in Skia mode

  • ellipsis with numberOfLines differs on Android native. Without numberOfLines, every renderer truncates to a single line. With it, Skia and iOS keep that many lines, but Android native still shows one.
  • Errors are not contained. Nothing in the renderer catches errors, so a failure while rendering propagates. paragraph.getPath is unimplemented on React Native Web, so stroked text throws there.
  • Box size differs from Android native. Skia adds strokeWidth to both axes; Android native adds strokeWidth * 2 + 4px to the width and nothing to the height. Layouts tuned against native Android can shift.

Migrating from 0.2.x

  • align defaults to 'left', not 'center', matching RN <Text>. Single-line text without a width sizes to itself, so it does not move. Pass align="center" where multi-line text, or text given a fixed width, should stay centred.
  • @shopify/react-native-skia is a required peer at 2.9.1, even if you only use mode="native".
  • Screen readers now read the text. Both renderers expose it as an accessible text element labelled with accessibilityLabel, or text when that is unset. If a parent view already carries the label, hide the stroke text from accessibility with importantForAccessibility="no-hide-descendants" and accessibilityElementsHidden.
  • iOS ellipsis with numberOfLines keeps that many lines. It used to show one.
  • New props: mode, letterSpacing, lineHeight, fontProvider and accessibilityLabel.

Development

yarn specs        # regenerate nitrogen bindings from src/specs/*.nitro.ts
yarn typescript   # compile src/ to lib/
yarn typecheck    # type-check without emitting

lib/ is gitignored but is published via the files field, so build it before packing. There is no prepare or prepack hook to do it for you.

To test a build inside an app before publishing, pack it and install the tarball:

npm pack --pack-destination <dir>
# then in the app: "@matiks/rn-stroke-text": "file:./.local-packages/<tarball>"

Bump the version before publishing — the registry already holds the current one.

Structure

  • src/ — TypeScript source. index.tsx picks the renderer, StrokeTextNative.tsx and StrokeTextSkia.tsx implement the two modes, specs/ holds the Nitro spec that nitrogen reads.
  • ios/ — Swift implementation (StrokeTextView, StrokedTextLabel).
  • android/ — Kotlin implementation and the CMake/Gradle build.
  • nitrogen/ — generated bindings; commit this folder.
  • nitro.json — nitrogen configuration and autolinking.