Skip to content

simonboisset/rn-variant

Repository files navigation

rn-variant

Light-weight, type-safe style variants for React Native. Inspired by Class Variance Authority and Unistyle, rn-variant lets you declare, combine and re-use complex styling options—with zero runtime dependencies.

Features

• Tiny & dependency-free – just TypeScript + StyleSheet. • Multi-variant syntax – compose size, color, state, etc. • Compound variants – attach styles to specific variant combos. • Boolean flags – declare rounded, disabled, etc. as simple booleans. • Strict typings – variant values are autocompleted and type-checked. • Hook-based API – const { style } = useVariants({ size: 'md', color: 'primary' }).

📦 Installation

npm install rn-variant

# or

yarn add rn-variant

⚡ Quick start

import { createVariantStyles } from "rn-variant";

/* 1. Declare your variants */
const buttonVariants = createVariantStyles({
  base: {
    borderRadius: 6,
    alignItems: "center",
    justifyContent: "center",
    paddingVertical: 12,
    paddingHorizontal: 24,
  },
  variants: {
    size: {
      sm: { paddingVertical: 8, paddingHorizontal: 16 },
      md: { paddingVertical: 12, paddingHorizontal: 24 },
      lg: { paddingVertical: 16, paddingHorizontal: 32 },
    },
    color: {
      primary: { backgroundColor: "#007bff" },
      secondary: { backgroundColor: "#6c757d" },
      outline: {
        backgroundColor: "transparent",
        borderWidth: 1,
        borderColor: "#007bff",
      },
    },
    rounded: {
      // boolean flag
      true: { borderRadius: 9999 },
      false: {},
    },
  },

  /* optional */
  compoundVariants: [
    {
      variants: { color: "primary", size: "lg" },
      style: { shadowOpacity: 0.25, shadowRadius: 4 },
    },
  ],
});

/* 2. Extract prop types (optional) */
import type { InferVariant } from "rn-variant";
export type ButtonVariantProps = InferVariant<typeof buttonVariants>;

/* 3. Use in a component */
export const Button = ({
  title,
  ...variant
}: ButtonVariantProps & { title: string; onPress?: () => void }) => {
  const { style } = buttonVariants.useVariants(variant);
  return (
    <TouchableOpacity style={style} onPress={variant.onPress}>
      <Text style={{ color: variant.color === "outline" ? "#007bff" : "#fff" }}>
        {title}
      </Text>
    </TouchableOpacity>
  );
};

API

createVariantStyles(options)

option type default description
base Partial<ViewStyle | TextStyle | ImageStyle> {} style applied to all variants
variants Record<group, Record<key, Partial<RNStyle>>> top-level variant groups (e.g. size, color)
compoundVariants Array<{ variants: Partial<variants>; style: Partial<RNStyle>; }> [] extra style when all matching keys are present

Returns:

{
  styles: { [Group in keyof variants]: { [Key in keyof variants[Group]]: { style: RNStyle } } };
  useVariants(input: VariantInput): { style: RNStyle };
}

useVariants(input)

Accepts an object where keys are variant groups and values are: • a variant key ('lg', 'primary', …), or • boolean when the group defines { true, false }.

It merges base → individual variants → matching compoundVariants and returns { style } ready for <View style={...} />.

InferVariant

Utility type that extracts the props shape expected by useVariants, handy for declaring component props.

📄 License

MIT © 2025 Simon Boisset

About

A lightweight, type-safe utility for managing style variants in React Native

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published