react-native-reusables icon indicating copy to clipboard operation
react-native-reusables copied to clipboard

[Feature Request] Compatibility with Uniwind (High-performance NativeWind alternative)

Open JerryBels opened this issue 1 month ago • 3 comments

A performance optimization opportunity! react-native-reusables currently relies on NativeWind. While NativeWind v4 is great, some users (myself included) are moving towards Uniwind for its significant performance benefits. Uniwind offers much faster styling resolution and better stability, while maintaining near-100% Tailwind compatibility. Also, it's by the team behind Unistyles, which is probably the most stable UI library for RN.

Currently, using RNR components with Uniwind requires manual refactoring for every component (e.g., swapping cssInterop for withUniwind, handling safe-area classes manually).

The opportunity

I would love to see official support for Uniwind, or at least a dedicated section in the documentation/CLI options to "Eject/Install for Uniwind."

Ideally, the CLI could offer a flag: npx react-native-reusables add button --styling=uniwind

If a full CLI integration is too much work right now, a "Using with Uniwind" guide in the docs would be an amazing first step. This guide could outline the standard replacements needed to make the components compatible.

What I'm currently doing

I am currently manually patching components as I add them. The process is consistent but tedious:

  1. Replacing cssInterop with withUniwind for Lucide icons.
  2. Replacing *-safe utility classes (which Uniwind doesn't support) with style={{ paddingBottom: insets.bottom }} via react-native-safe-area-context.
  3. Ensuring all Reanimated props (like entering) use object syntax rather than string syntax.

Additional context

Uniwind is created by Jacek Pudysz (creator of Unistyles) and is gaining traction for high-performance Expo apps.

  • Repo: https://github.com/Unistyles-OSS/uniwind
  • Why it fits RNR: RNR's "copy-paste" architecture is actually perfect for this, as users own the code. We just need a "Uniwind-flavored" version of the base components.

Thanks for the amazing library! Adding Uniwind support would make RNR the go-to choice for high-performance/heavy-duty RN apps.

JerryBels avatar Nov 18 '25 16:11 JerryBels

+1

eyupk3 avatar Nov 19 '25 16:11 eyupk3

Any further thoughts on this?

Bartek532 avatar Nov 28 '25 09:11 Bartek532

On it's way. For those curious, here is the mostly completed WIP: https://github.com/mrzachnugent/rnr-uniwind-test

mrzachnugent avatar Nov 28 '25 17:11 mrzachnugent

FYI I basically already use all RNR components in my Uniwind project, and I fixed the small issues VERY easily, even targeting batch updates through AI - it was completely painless :)

JerryBels avatar Nov 29 '25 15:11 JerryBels

I tried migrating to Uniwind but RNR Text component won't render. @JerryBels do you have a working example?

jinsley8 avatar Dec 01 '25 17:12 jinsley8

Sure, here you go:

import { cn } from '@/lib/utils';
import * as Slot from '@rn-primitives/slot';
import { cva, type VariantProps } from 'class-variance-authority';
import * as React from 'react';
import { Text as RNText } from 'react-native';

const textVariants = cva('text-foreground text-base', {
  variants: {
    variant: {
      default: 'text-base max-sm:text-sm',
      // other variants
    },
  },
  defaultVariants: {
    variant: 'default',
  },
});

type TextVariantProps = VariantProps<typeof textVariants>;

const TextClassContext = React.createContext<string | undefined>(undefined);

function Text({
  className,
  asChild = false,
  variant = 'default',
  ...props
}: React.ComponentProps<typeof RNText> &
  TextVariantProps &
  React.RefAttributes<RNText> & {
    asChild?: boolean;
  }) {
  const textClass = React.useContext(TextClassContext);
  const Component = asChild ? Slot.Text : RNText;

  // If a variant other than 'default' is explicitly set, don't apply context styles
  // to prevent context from overriding explicit variant choices
  const shouldApplyContext = variant === 'default';
  const finalClassName = cn(textVariants({ variant }), shouldApplyContext ? textClass : undefined, className);

  return (
    <Component
      className={finalClassName}
      {...props}
    />
  );
}

export { Text, TextClassContext };
export type { TextVariantProps };

JerryBels avatar Dec 01 '25 23:12 JerryBels