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

@variantlabs/react

v0.2.0-alpha.2

Published

VariantLabs React bindings: <VariantLabsProvider>, useVariant, useOutcome, <Variant>

Readme

@variantlabs/react

npm license

React bindings for VariantLabs — a provider, hooks, and a render-prop component for feature flags, experiments, and AI config.

Install

npm install @variantlabs/react

React 18 or 19 is a peer dependency. @variantlabs/js comes along as a dependency — you don't need to install it separately.

Quickstart

Build the client, pass it to the provider:

import { initVariantLabs, VariantLabsProvider } from "@variantlabs/react"

const vl = initVariantLabs({
  apiKey: import.meta.env.VITE_VARIANTLABS_KEY,
  appKey: "web",
  environmentKey: "production",
})

export function App() {
  return (
    <VariantLabsProvider client={vl}>
      <Checkout />
    </VariantLabsProvider>
  )
}

Then read variants anywhere below it:

import { useVariant } from "@variantlabs/react"

function Checkout() {
  const { value, isLoading } = useVariant("checkout-button-color", undefined, "blue")

  if (isLoading) return <Skeleton />
  return <button style={{ background: value as string }}>Buy now</button>
}

Create the client outside your component tree so it isn't recreated on every render.

useVariant

const { value, variantKey, isLoading, assignment } = useVariant(configKey, ctx?, fallback?)

Once the provider is ready, this resolves synchronously from the local cache — no loading flash for returning visitors. Before that it awaits the client, returning fallback in the meantime. If evaluation fails for any reason it returns fallback rather than throwing.

// With targeting context
const { value } = useVariant("pricing-tier", { subjectKey: user.id, attributes: { plan: user.plan } })

// Typed
const { value } = useVariant<{ headline: string }>("hero-copy", undefined, { headline: "Welcome" })

The ctx object is compared by stable hash, so an inline literal won't cause a re-evaluation loop.

useOutcome

Returns a stable tracker function — safe in dependency arrays.

import { useOutcome, useVariant } from "@variantlabs/react"

function BuyButton() {
  const { assignment } = useVariant("checkout-flow")
  const track = useOutcome()

  return (
    <button
      onClick={() => {
        track({
          assignmentId: assignment!.assignmentId,
          outcomeKey: "purchase",
          success: true,
          numericValue: 49.99,
        })
      }}
    >
      Buy now
    </button>
  )
}

<Variant>

A render-prop component, for when a hook would mean splitting out a component just to call it.

import { Variant } from "@variantlabs/react"

<Variant
  configKey="homepage-hero"
  fallback={<DefaultHero />}
  render={(assignment, value) => <Hero {...(value as HeroProps)} />}
/>

fallback renders while loading and if evaluation fails.

useVariantLabsClient

Escape hatch to the underlying @variantlabs/js client — for imperative calls like flush() or evaluating outside of render.

const client = useVariantLabsClient()
await client?.flush()

Fails open, always

If client.init() rejects — network down, bad key, API unreachable — the provider still flips to ready. Hooks then render their fallbacks instead of suspending forever or throwing. A VariantLabs outage degrades to your default experience; it never takes down your app.

Next.js and RSC

The build prepends "use client", so these components work in the App Router without extra wrapping.

For server-side evaluation — baking a variant into SSR HTML with no client flash — use @variantlabs/node in a server component and pass the result down as props. The Next.js example shows both halves working together.

API

| | | | --- | --- | | <VariantLabsProvider client> | Context provider; calls init() | | useVariant(key, ctx?, fallback?) | { value, variantKey, isLoading, assignment } | | useOutcome() | Stable (input) => void tracker | | useVariantLabsClient() | The underlying client, or null | | <Variant configKey ctx? fallback? render> | Render-prop component | | VariantLabsContext | Raw context, for custom hooks |

initVariantLabs and the core types (AssignmentResult, EvaluationContext, TrackOutcomeInput, VariantValue, …) are re-exported, so you only import from this package.

Compatibility

React 18 / 19. Node >= 22 for tooling. Ships ESM + CJS + type declarations.

License

Apache-2.0