# RN Primitives: unstyled React Native components where accessibility is the point

> RN Primitives is a pnpm and turbo monorepo of style agnostic React Native components for iOS, Android and web, covering 28 core primitives plus shared hooks, portal, slot, types and utils, with an explicit accessibility focus. It fits teams that want accessible behaviour without inheriting a design system, and it does not fit projects that want a themed, drop-in component kit.

**roninoss/rn-primitives** — Style-agnostic, accessible React Native components for iOS, Android, and Web

- Repository: https://github.com/roninoss/rn-primitives
- Website: https://rnprimitives.com
- Stars: 945 · Forks: 55
- Language: TypeScript
- License: MIT
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/roninoss-rn-primitives

## The components ship without styles on purpose

RN Primitives describes itself as universal style agnostic and accessible React Native components, and the first thing the project explains is its unstyled nature. The components come without any predefined styles by default, which is presented as freedom rather than as a missing feature: you match the components to your app's aesthetics instead of overriding someone else's design decisions.

That choice has a real cost and a real benefit, and it helps to be honest about both. The benefit is that a component library that ships no styling cannot fight your theme, your spacing scale or your brand colour, and it cannot drift out of sync with a design system you did not choose. The cost is that nothing looks finished until you style it, and every screen you build needs a decision about focus rings, hit areas, disabled states and typography that a themed kit would have made for you.

The scope is broad. The core list covers accordion, alert-dialog, aspect-ratio, avatar, checkbox, collapsible, context-menu, dialog, dropdown-menu, hover-card, label, menubar, navigation-menu, popover, progress, radio-group, select, separator, slider, switch, table, tabs, toast, toggle, toggle-group, toolbar and tooltip, which is 28 primitives covering everything from a simple separator to the composite patterns a menu system needs. The shared layer adds hooks, portal, slot, types and utils, and those five are where the interesting cross-platform work lives.

## Accessibility is a stated design constraint, with the web side lagging

Accessibility is described as a significant focus within the project, and the wording is careful. The stated effort involves designing and testing components with appropriate labels, roles and behaviours, aiming at an inclusive user experience. The word ongoing matters here, because the release history shows the same thing.

Version 1.5.1 is titled Accessibility overhaul (native only; .web.tsx untouched), dated 2026-07-02, and version 1.5.2 followed the same day as Additional Bug Fixes. The next release, portal@1.5.3, is dated 2026-08-08. So an accessibility pass landed across the native implementations in one release, and the web implementations were explicitly left out of it.

That is the most important single fact for anyone evaluating this library for a cross-platform app. A React Native product that ships to iOS, Android and web gets a component set whose native accessibility work is current and whose web behaviour is on the previous footing. The naming convention in the release title, .web.tsx, implies a per-platform file structure in which each primitive has a native implementation and a web variant, and the overhaul simply did not cover the latter.

Whether that matters depends on your web users. If the web build is a secondary target, you can live with it. If web is where most of your traffic sits, then the accessibility story of the library is uneven across the platforms it advertises, and you would need to audit the web variants yourself.

## A pnpm and turbo monorepo with changesets driving the releases

The repository is a workspace monorepo, and the toolchain tells you a lot about how the project is maintained. The root is @rn-primitives/monorepo, marked private, with pnpm-lock.yaml, pnpm-workspace.yaml and turbo.json at the top level, alongside packages/ for the primitives and apps/ for the example and documentation applications.

Turbo drives every task, and the scripts are organised as filters over the workspace.

```json
    "dev:primitives": "turbo dev --filter=./packages/* --concurrency=33",
    "dev:expo-nativewind": "turbo dev --filter=./apps/expo-nativewind",
    "dev:nextjs-nativewind": "turbo dev --filter=./apps/nextjs-nativewind",
    "dev:docs": "turbo dev --filter=./apps/docs",
```

Note the filters. The apps directory holds an Expo app with NativeWind, a Next.js app with NativeWind, an Expo app using StyleSheet, and the documentation app, so the primitives are exercised against three different styling approaches and one docs site rather than one example. That is a reasonable proxy for the claim that the components are style agnostic, since a component that only works with one styling approach would show up immediately.

Releases are managed with changesets. The version-bump script runs npx changeset and then npx changeset version, and the publish scripts fan out across all packages with separate next and beta channels, which is how a monorepo publishes twenty-odd packages in lockstep without a hand-written release script.

## Contributing means building the packages in watch mode and running an app

The contributor setup is a three-step loop, and the second step is the one that matters. You fork, clone and install the dependencies with pnpm.

```bash
pnpm i
```

Then you build and watch all of the primitive packages.

```bash
pnpm dev:primitives
```

The documentation explains why this exists: it builds all of the primitive packages and watches them for changes, which prevents the need to run the build command every time a primitive file is changed. Without it, a change to a primitive means a rebuild before the app picks it up, and the feedback loop on a component library is short by nature.

Finally you start whichever application you want to look at.

```bash
# Start the Expo NativeWind app
pnpm dev:expo-nativewind
# Or start the Nextjs NativeWind app
pnpm dev:nextjs-nativewind
# Or the Documentation app
pnpm dev:docs
```

The build and lint and test entry points are all turbo tasks over the workspace, with test running turbo test, lint running turbo lint, and build filtering to the packages directory. The toolchain floor is explicit in the manifest: node >=20.11.0, pnpm 9.1.4 as the package manager, typescript at ^5.8.3, turbo at ^2.0.1 and @changesets/cli at ^2.29.2.

## The five shared packages are where the cross-platform work is

Twenty-eight core primitives would be a lot of surface area to maintain by hand, and the shared layer is what keeps them consistent. Five packages sit underneath: hooks, portal, slot, types and utils.

Their names describe their jobs, but the interesting question is what they enable rather than what they contain, and the repository does not document their internals in the project page. The reason to care is structural. A portal primitive, for instance, is the mechanism by which an overlay such as a dialog, a popover, a tooltip, a hover-card, a context-menu or a toast can render outside the bounds of its parent, which is the requirement that makes those patterns work on all three platforms. A slot primitive is the composition mechanism that lets a consumer pass their own component through to the element that needs the behaviour, which is how an unstyled library hands control back to the developer without losing the accessibility wiring.

The types package is worth a mention for a different reason. In an unstyled library, the props are the API surface, and the type definitions are where that surface is documented, since the components carry no visual defaults to inspect.

None of this is documented in prose in the project page, so if the exact contract of slot or portal matters to your integration, the packages themselves and the documentation site at rnprimitives.com are where you have to look.

## MIT licensed, versioned per package, and a recent but not continuous history

The licence field on the repository says MIT, which is a permissive grant with no requirement to publish your own source when you use the components in an application. Reading the LICENSE file for the exact terms is still the sensible step before shipping, and none of this is legal advice.

Versioning is per package rather than for the repository as a whole, and that is worth understanding before you plan an upgrade. The recent releases are named by package: portal@1.5.3, then all@1.5.2, then all@1.5.1 with the accessibility overhaul title. The all package is the bundle that aggregates the primitives, and individual packages such as portal version independently. In practice that means the version of a primitive you depend on is not necessarily the version of the aggregate you see in the release feed, so a lockfile check across your own dependencies is the only reliable way to know what you are on.

On maintenance, the last push was on 2026-08-08 and the repository is not archived. The releases around that date, 1.5.1 and 1.5.2 in July and portal 1.5.3 in August, show recent work, and the changeset-based release process with next and beta publish channels is a setup built for a steady flow of package releases. The gap between the two 1.5.1 and 1.5.2 tags on the same day suggests the sort of quick follow-up release you get when an accessibility change needs a fix rather than a planned version boundary.

The documentation site at rnprimitives.com is the home page for the project, and the docs app in the repository is the same content served locally.

## Conclusion

Adopt RN Primitives when your team needs accessible React Native behaviour for iOS, Android and web without adopting someone else's visual design, and when you are prepared to own the styling layer. Do not adopt it expecting a themed component library, since the components ship without predefined styles by design. Before building on it, check which primitives you need against the list, because the accessibility overhaul in version 1.5.1 was native only and left the .web.tsx implementations untouched, confirm your toolchain matches node >=20.11.0 and pnpm 9.1.4, and note that the last push was on 2026-08-08.

## FAQ

### Are RN Primitives components styled?

No. The project describes them as unstyled, with no predefined styles by default, so that developers can match the components to their own app's aesthetics. The styling work is left to the consuming project.

### Which platforms does RN Primitives support?

iOS, Android and web. The repository contains separate app examples for an Expo app with NativeWind, a Next.js app with NativeWind, an Expo app using StyleSheet, and the documentation app, and primitives use per-platform files such as .web.tsx.

### What changed in the RN Primitives 1.5.1 accessibility overhaul?

The release title states it explicitly: Accessibility overhaul (native only; .web.tsx untouched), dated 2026-07-02. The web implementations were not part of that pass, so the accessibility work is not at the same level across platforms.

### How do I run the RN Primitives packages locally?

Install the dependencies with pnpm i, then run pnpm dev:primitives to build and watch all of the primitive packages, and start one of the apps with pnpm dev:expo-nativewind, pnpm dev:nextjs-nativewind or pnpm dev:docs. The watch mode avoids rebuilding after every change to a primitive.

### How are RN Primitives versions published?

The monorepo uses changesets, with the version-bump script running npx changeset and npx changeset version, and separate turbo publish scripts for the next and beta channels across all packages. Because versions are per package, a release such as portal@1.5.3 can move independently of the all bundle.

## Sources

- [License: MIT](https://github.com/roninoss/rn-primitives/blob/main/LICENSE)
- [Project website](https://rnprimitives.com)
- [README](https://github.com/roninoss/rn-primitives/blob/main/README.md)
- [Releases](https://github.com/roninoss/rn-primitives/releases)
- [roninoss/rn-primitives on GitHub](https://github.com/roninoss/rn-primitives)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/roninoss-rn-primitives
