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

@rapidshift/react-preview-lock

v1.0.0

Published

A minimal React password gate for private demos and website previews by Rapid Shift.

Readme

Rapid Shift Preview Lock

A minimal React password gate for private demos and website previews.

@rapidshift/react-preview-lock puts a clean, brand-ready password screen in front of a React website — and lets you switch it off with a single environment variable when the site goes public. No accounts, no backend, no UI framework.

<PreviewLock>
  <App />
</PreviewLock>

Why Preview Lock?

You send a demo website to a prospective client and you just want a light gate in front of it until it's approved.

Preview Lock is a lightweight access gate for demos and staging websites. It is not a replacement for server-side authentication.

It's perfect for client demos, speculative concepts, staging sites, and portfolio previews. It is not for protecting confidential data, real user accounts, admin systems, or anything requiring genuine authorization. Because the check runs in the browser, a technically knowledgeable person can inspect the bundle and bypass it. That trade-off is the point — the selling point is simplicity.

Installation

npm install @rapidshift/react-preview-lock

Quick Start

import { PreviewLock } from '@rapidshift/react-preview-lock';

function App() {
  return (
    <PreviewLock>
      <MyWebsite />
    </PreviewLock>
  );
}

Add two variables to your .env:

LOGIN_ENABLED=true
LOGIN_PASSWORD=my-preview-password

Then add the small Vite snippet below. That's it — styles are bundled automatically, nothing else to import.

LOGIN_ENABLED=false completely bypasses the password screen and renders your site directly. Use this when the client's site is approved and should become publicly accessible.

Environment Variables

| Variable | Values | Meaning | | ---------------- | --------------- | ------------------------------------------------ | | LOGIN_ENABLED | true / false| Show the gate, or render the site directly. | | LOGIN_PASSWORD | any string | The password a visitor must enter to unlock. |

Vite Configuration

Vite does not expose arbitrary variables (like LOGIN_PASSWORD) to the browser. Map just these two values into compile-time constants in your vite.config.ts:

import { defineConfig, loadEnv } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig(({ mode }) => {
  const env = loadEnv(mode, process.cwd(), '');
  return {
    plugins: [react()],
    define: {
      __PREVIEW_LOCK_ENABLED__: JSON.stringify(env.LOGIN_ENABLED ?? 'false'),
      __PREVIEW_LOCK_PASSWORD__: JSON.stringify(env.LOGIN_PASSWORD ?? ''),
    },
  };
});

Only the two required values are exposed — never the whole environment.

Using VITE_* variables instead

Prefer not to touch vite.config.ts? Vite exposes any VITE_-prefixed variable automatically, so you can skip the snippet entirely:

VITE_LOGIN_ENABLED=true
VITE_LOGIN_PASSWORD=my-secret-password

Preview Lock reads both styles out of the box. If both are present, the define values take precedence.

Component Props

The default works with zero UI configuration. Everything is optional:

<PreviewLock
  title="Private Preview"
  description="Enter the password provided by Rapid Shift."
  buttonText="View Preview"
/>

| Prop | Type | Default | Description | | ------------- | ------------------------- | ----------------------------- | ------------------------------------------------------- | | children | ReactNode | — | The protected app, rendered once unlocked. | | title | string | "Private Preview" | Heading on the password screen. | | description | string | see default copy | Supporting text under the heading. | | buttonText | string | "View Preview" | Submit button label. | | logo | ReactNode | RAPID SHIFT wordmark | Replace the default wordmark with your own node. | | password | string | from env | Explicit password (overrides env). | | enabled | boolean | from env, else false | Explicitly enable/disable the gate (overrides env). | | storage | "session" | "local" | "session" | Where the unlocked flag is persisted. | | storageKey | string | "rapidshift-preview-lock" | Storage key for the unlocked flag. | | className | string | — | Extra class on the fullscreen overlay. | | footer | ReactNode | Created by Rapid Shift | Replace the footer content. | | onUnlock | () => void | — | Called once, right after a successful unlock. |

Configuration priority: explicit prop → environment → safe default (enabled=false, no password). If the gate is enabled but no password is configured, Preview Lock fails safely: it stays locked and logs a development-only warning — it never unlocks by accident.

Both PreviewLock and the alias RapidShiftPreviewLock are exported.

Session vs Local Storage

After a correct password, Preview Lock stores a flag (rapidshift-preview-lock=authenticated) so reloads during the same session stay unlocked. The password itself is never stored.

  • session (default): access ends naturally when the browser/tab session closes.
  • local: access persists across sessions until storage is cleared.

Custom Branding

<PreviewLock
  logo={<img src="/logo.svg" alt="Acme" height={28} />}
  title="Acme — Private Preview"
  description="Enter the password we shared with you."
  footer={<a href="https://acme.example">Prepared by Acme</a>}
/>

Examples

Explicit config (great for testing):

<PreviewLock enabled password="demo123">
  <App />
</PreviewLock>

Persist across sessions:

<PreviewLock storage="local">
  <App />
</PreviewLock>

A full Vite + React + TypeScript demo lives in example/vite-react.

From Preview to Production

The reason this package exists — no component code changes between states.

During client presentation:

LOGIN_ENABLED=true
LOGIN_PASSWORD=client-password

→ Visitors get the Private Preview screen and must enter the password.

After client approval, change only one line and redeploy:

LOGIN_ENABLED=false

→ The public website renders directly, with no login screen.

Security

Preview Lock is client-side by design. Anyone with the JavaScript bundle can potentially read the password or bypass the gate. Use it for previews and demos, not for confidential information, real authentication, or authorization. For anything sensitive, use server-side auth.

Keep previews out of search engines

This is separate from password protection. To stop speculative previews being indexed, add to your HTML <head>:

<meta name="robots" content="noindex, nofollow, noarchive" />

and optionally a robots.txt:

User-agent: *
Disallow: /

Preview Lock never touches your site's SEO settings for you.

TypeScript

Written in TypeScript with bundled type declarations — no @types package needed. Import the props type when you need it:

import type { PreviewLockProps } from '@rapidshift/react-preview-lock';

Development

npm install
npm run dev         # build in watch mode
npm test            # run tests
npm run lint        # lint
npm run typecheck   # type-check
npm run build       # build ESM + declarations

Requires React 18 or 19 (declared as peer dependencies, so you never get a second copy of React).

Publishing

Releases are published to npm through GitHub Actions using npm Trusted Publishing (OIDC) — no long-lived npm token is stored. Publishing only happens when you create a GitHub Release.

Release process:

  1. Make your changes.
  2. Run npm run lint && npm run typecheck && npm test && npm run build.
  3. Bump the version and update CHANGELOG.md (npm version patch|minor|major).
  4. Push the tag and create a GitHub Release.
  5. The Publish workflow builds and runs npm publish with provenance.

See RELEASING.md for the exact one-time npm setup and step-by-step release instructions.

License

MIT © Rapid Shift Ltd

Rapid Shift

Built by Rapid Shift — a digital agency & media production studio in Cyprus.

Elevate. Engage. Evolve. — Let's make the shift.