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

react-access-kit

v1.1.2

Published

Type-safe React access gates with roles, persistence, expiry, and custom prompts.

Readme

react-access-kit

npm version license

The fastest way to ship polished, role-aware access flows in React—without committing your app to a heavyweight auth UI framework.

Drop in one component for a useful default, or take complete control with a provider, a headless hook, custom storage, and server-backed authorization. Your users get a smooth unlock flow; your team gets a small, typed API that fits the stack you already have.

react-access-kit is a presentation-layer access gate. Pair it with server-side authorization for sensitive data and actions.

Why developers choose it

| You need… | You get… | | --------------------------------- | ----------------------------------------------------------------------------------------------------------- | | A gate today | A copy-paste <AccessGate> that works immediately. | | A gate that does not look generic | Your own components through renderPrompt, or complete markup freedom with useAccessGate. | | Several protected areas | One AccessProvider that shares access state, persistence, and timers across the app. | | A bridge to real auth | An async authorize callback that lets your backend make the final decision. | | A dependable developer experience | TypeScript-first APIs, accessible defaults, expiry that survives reloads, and zero runtime UI dependencies. |

Small by default. Capable when needed.

Most libraries make you choose between a rigid drop-in widget and building every detail yourself. react-access-kit gives you both paths in one focused package:

  • Use the built-in prompt when speed matters.
  • Swap in your design system when product polish matters.
  • Go headless when the interaction is uniquely yours.
  • Keep your backend in control when access has real security implications.

That means less glue code, fewer one-off dialogs, and a clean upgrade path as your application grows.

Installation

npm install react-access-kit

Quick start

One component is enough for a complete access flow:

import { AccessGate } from "react-access-kit";

export function AdminArea() {
  return (
    <AccessGate
      roles={{ admin: "demo-password" }}
      role="admin"
      timeoutMinutes={15}
      loadingFallback={<p>Restoring access…</p>}
    >
      <AdminDashboard />
    </AccessGate>
  );
}

Shared state with AccessProvider

Wrap an application area in AccessProvider when several gates should share one source of truth, timer set, and storage entry. Gates inside the provider only need a role—no prop drilling, duplicated timers, or competing storage writes.

import { AccessGate, AccessProvider } from "react-access-kit";

export function App() {
  return (
    <AccessProvider
      roles={{ admin: "demo-password", analyst: "reports-password" }}
      timeoutMinutes={30}
      storageKey="my-product-access"
    >
      <AccessGate role="admin">
        <AdminDashboard />
      </AccessGate>
      <AccessGate role="analyst">
        <Reports />
      </AccessGate>
    </AccessProvider>
  );
}

Server-backed authorization

For sensitive capabilities, keep authorization on your server while retaining the same great component API. authorize may return a boolean or { allowed, expiresAt }; the latter lets your server control the exact session expiry.

<AccessGate
  role="admin"
  authorize={async ({ role, password }) => {
    const response = await fetch("/api/access/unlock", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ role, password }),
    });

    const result = await response.json();
    return {
      allowed: result.allowed,
      expiresAt: result.expiresAt,
    };
  }}
>
  <AdminDashboard />
</AccessGate>

Custom prompt

Use renderPrompt to integrate your design system without adapter components or styling overrides. It receives submitting as well as errors from failed passwords, missing roles, or failed authorization.

<AccessGate
  roles={{ editor: "edit" }}
  role="editor"
  title="Editor access"
  renderPrompt={({ title, onSubmit, error, submitting }) => (
    <form
      onSubmit={(event) => {
        event.preventDefault();
        const password = new FormData(event.currentTarget).get("password");
        void onSubmit(String(password ?? ""));
      }}
    >
      <h2>{title}</h2>
      <input name="password" type="password" autoComplete="current-password" />
      <button disabled={submitting}>
        {submitting ? "Checking…" : "Continue"}
      </button>
      {error && <p role="alert">{error}</p>}
    </form>
  )}
>
  <Editor />
</AccessGate>

Headless API

useAccessGate is for fully custom UIs. It must be called inside an AccessProvider.

import { useAccessGate } from "react-access-kit";

function AdminUnlockButton() {
  const { status, error, submitting, submit } = useAccessGate({
    role: "admin",
  });

  if (status === "authorized") return <AdminDashboard />;

  return (
    <button disabled={submitting} onClick={() => void submit("demo-password")}>
      {error ?? "Unlock admin"}
    </button>
  );
}

API reference

AccessGate and AccessProvider options

AccessProvider accepts every access option below. AccessGate accepts the same options when used without a provider; inside a provider, its access options are supplied by the provider.

| Option | Type | Default | Description | | ----------------- | ------------------------ | ------------------------- | ---------------------------------------------------------------------------------- | | roles | Record<string, string> | {} | Local role/password map. Best suited to demos or non-sensitive UI gating. | | role | string | required on AccessGate | Role required to render children. | | authorize | Authorize | optional | Sync or async server-side validator. | | persist | boolean | true | Persist unlocked roles through the configured storage adapter. | | storage | Storage \| null | localStorage | Custom storage adapter, or null to disable browser storage. | | storageKey | string | react-access-kit-access | Key used for persisted access. Use a unique key per app. | | secretKey | string | built-in | Key material used to encrypt browser data. Rotating it invalidates saved sessions. | | timeoutMinutes | number | optional | Expiry from successful local authorization. Persisted expiry survives reloads. | | loadingFallback | ReactNode | null | Rendered while saved state is restored. | | onSuccess | () => void | optional | Called after a successful unlock. | | renderPrompt | function | optional | Custom prompt renderer. |

useAccess

Use useAccess for imperative flows. It returns:

| Member | Description | | ----------------------------- | -------------------------------------------------------------------------------- | | unlockedRoles | Currently unlocked roles. | | hasAccess(role) | Whether the role is currently unlocked. | | isRoleConfigured(role) | Whether a local role or an authorize callback can validate it. | | unlock(role, password) | Synchronous local-password unlock. | | unlockAsync(role, password) | Unlocks with authorize when configured; otherwise uses the local password map. | | lock(role?) | Locks a role, or all roles without an argument. | | loading | true while persisted access is being restored. |

Accessibility

The built-in PasswordPrompt provides a labeled password field, password-manager autocomplete, focus on open, disabled submission while verification is pending, and an announced error message. Custom prompts should offer equivalent semantics.

Persistence and security

Persisted access is encrypted before it is placed in browser storage. A positive timeoutMinutes stores an exact expiry timestamp and re-locks the role after refresh. Older role-array sessions remain readable for backwards compatibility.

Browser code, client-side passwords, and rendered JavaScript can be inspected by users. Do not rely on this package alone to protect sensitive data, payments, administrative actions, or API endpoints. Always enforce authentication and authorization on the server.

Development

npm test
npm run build

License

MIT