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

@hawcx/react

v2.4.1

Published

React bindings for the Hawcx headless SDK.

Readme

@hawcx/react

React bindings for Hawcx Auth. Provides hooks and a drop-in component for authentication flows.

Installation

npm install @hawcx/react

Quick Start

Option 1: Drop-in Component

Add complete authentication UI with minimal code:

import { HawcxProvider, HawcxSignUpSignIn } from '@hawcx/react';
import '@hawcx/react/dist/styles.css';

function App() {
  return (
    <HawcxProvider config={{ configId: 'your-config-id' }}>
      <HawcxSignUpSignIn
        onSuccess={(authCode) => {
          // Exchange authCode for tokens on your backend
          fetch('/api/auth/token', {
            method: 'POST',
            body: JSON.stringify({ code: authCode }),
          });
        }}
      />
    </HawcxProvider>
  );
}

Option 2: Custom UI with Hooks

Build your own UI using the provided hooks:

import { HawcxProvider, useAuthState, useAuthActions } from '@hawcx/react';

function App() {
  return (
    <HawcxProvider config={{ configId: 'your-config-id' }}>
      <LoginForm />
    </HawcxProvider>
  );
}

function LoginForm() {
  const state = useAuthState();
  const { start, selectMethod, submitCode } = useAuthActions();

  if (state.status === 'completed') {
    return <div>Authenticated!</div>;
  }

  // Render UI based on state.status and state.step.type
  // ...
}

Provider

Wrap your app with HawcxProvider:

import { HawcxProvider } from '@hawcx/react';

<HawcxProvider config={{
  configId: 'your-config-id',
  apiBase: 'http://localhost:7998/v1', // Optional
  logger: console,                      // Optional, for debugging
}}>
  {children}
</HawcxProvider>

Or provide a pre-created client:

import { createHawcxClient } from '@hawcx/core';

const client = createHawcxClient({ configId: 'your-config-id' });

<HawcxProvider client={client}>
  {children}
</HawcxProvider>

Hooks

useAuthState()

Get the current auth state and subscribe to changes:

const state = useAuthState();

switch (state.status) {
  case 'idle':
    return <StartForm />;
  case 'loading':
    return <Spinner />;
  case 'step':
    return <RenderStep step={state.step} />;
  case 'completed':
    return <Success authCode={state.authCode} />;
  case 'error':
    return <Error message={state.error.message} />;
}

useAuthActions()

Access all client action methods:

const actions = useAuthActions();

// Start a flow
await actions.start('signin', '[email protected]');

// Select an auth method
await actions.selectMethod('email_otp');

// Submit OTP code
await actions.submitCode('123456');

// Submit TOTP code
await actions.submitTotp('123456');

// Submit phone for SMS enrollment
await actions.submitPhone('+14155551234');

// Request new code
await actions.resend();

// Cancel flow
await actions.cancel();

// Reset to idle
actions.reset();

// Sign out
actions.signOut();

useAuthFlags()

Boolean flags for state checking:

const { isIdle, isLoading, isStep, isCompleted, isError } = useAuthFlags();

if (isLoading) {
  return <Spinner />;
}

useSession()

Access and manage the authentication session:

const { session, isLoading, error, actions } = useSession();

if (session) {
  // User is authenticated
  // session.authCode - exchange for tokens
  // session.codeVerifier - for PKCE
}

// Sign out
actions.signOut();

useAuthClient()

Access the underlying HawcxClient instance:

const client = useAuthClient();

// Direct client access for advanced use cases
const hasCreds = await client.hasDeviceCredentials('[email protected]');

Form Hooks

Pre-built form state management for common UI patterns.

useIdentifierForm(options)

Manage the email/phone input form:

function LoginStart() {
  const { identifier, setIdentifier, isSubmitting, submit } = useIdentifierForm({
    flowType: 'signin', // or 'signup'
  });

  return (
    <form onSubmit={(e) => { e.preventDefault(); submit(); }}>
      <input
        type="email"
        value={identifier}
        onChange={(e) => setIdentifier(e.target.value)}
        placeholder="Email"
      />
      <button type="submit" disabled={isSubmitting}>
        Continue
      </button>
    </form>
  );
}

useOtpForm()

Manage OTP/TOTP input. Auto-detects regular OTP vs TOTP:

function OtpInput() {
  const {
    code,
    setCode,
    submit,
    resend,
    destination,   // Masked email/phone for OTP
    isTotp,        // True if TOTP (not regular OTP)
    isSubmitting,
  } = useOtpForm();

  return (
    <form onSubmit={(e) => { e.preventDefault(); submit(); }}>
      {destination && <p>Code sent to {destination}</p>}
      <input
        type="text"
        value={code}
        onChange={(e) => setCode(e.target.value)}
        placeholder={isTotp ? 'Authenticator code' : 'Enter code'}
        maxLength={6}
      />
      <button type="submit" disabled={isSubmitting}>Verify</button>
      {!isTotp && <button type="button" onClick={resend}>Resend</button>}
    </form>
  );
}

usePhoneForm()

Manage phone number input for SMS enrollment:

function PhoneInput() {
  const { phone, setPhone, submit, isSubmitting } = usePhoneForm();

  return (
    <form onSubmit={(e) => { e.preventDefault(); submit(); }}>
      <input
        type="tel"
        value={phone}
        onChange={(e) => setPhone(e.target.value)}
        placeholder="+1 555 123 4567"
      />
      <button type="submit" disabled={isSubmitting}>Continue</button>
    </form>
  );
}

useMethodSelection(state)

Extract methods from a select_method step:

function MethodSelector() {
  const state = useAuthState();
  const { methods } = useMethodSelection(state);
  const { selectMethod } = useAuthActions();

  return (
    <div>
      {methods.map((method) => (
        <button key={method.name} onClick={() => selectMethod(method.name)}>
          {method.label}
        </button>
      ))}
    </div>
  );
}

useMethodDisplayName(method)

Get a display name for a method:

const label = useMethodDisplayName(method); // method.label or method.name

Drop-in Component

HawcxSignUpSignIn

Complete authentication UI with unified sign-in flow:

import { HawcxSignUpSignIn } from '@hawcx/react';
import '@hawcx/react/dist/styles.css';

<HawcxSignUpSignIn
  onSuccess={(authCode) => {
    // Exchange code for tokens
  }}
  className="my-auth-form"    // Optional custom class
/>

The component handles:

  • Unified sign-in flow (server determines new vs existing user)
  • Email/phone identifier input
  • Method selection
  • OTP input with resend
  • TOTP setup with QR code
  • SMS phone enrollment
  • QR code display for push/QR auth
  • Loading states
  • Error display

Building Custom UI

Example of a complete custom auth form:

import {
  HawcxProvider,
  useAuthState,
  useAuthActions,
  useAuthFlags,
  getStepType,
  getMethods,
  isEnterCodeStep,
  isSetupTotpStep,
} from '@hawcx/react';

function AuthFlow() {
  const state = useAuthState();
  const actions = useAuthActions();
  const { isLoading, isCompleted, isError } = useAuthFlags();

  if (isCompleted) {
    return <Success authCode={state.authCode} />;
  }

  if (isError) {
    return <Error error={state.error} onRetry={actions.reset} />;
  }

  if (isLoading) {
    return <Spinner />;
  }

  const stepType = getStepType(state);

  switch (stepType) {
    case null:
      return <IdentifierInput onSubmit={(email) => actions.start('signin', email)} />;

    case 'select_method':
      return (
        <MethodList
          methods={getMethods(state)}
          onSelect={actions.selectMethod}
        />
      );

    case 'enter_code':
      return (
        <OtpInput
          destination={state.step.destination}
          onSubmit={actions.submitCode}
          onResend={actions.resend}
        />
      );

    case 'enter_totp':
      return <TotpInput onSubmit={actions.submitTotp} />;

    case 'setup_totp':
      return (
        <TotpSetup
          secret={state.step.secret}
          otpauthUrl={state.step.otpauthUrl}
          onSubmit={actions.submitTotp}
        />
      );

    case 'setup_sms':
      return <PhoneInput onSubmit={actions.submitPhone} />;

    case 'await_approval':
      return <WaitingForApproval qrData={state.step.qrData} />;

    default:
      return <div>Unknown step: {stepType}</div>;
  }
}

Styling

Import the default styles:

import '@hawcx/react/dist/styles.css';

CSS classes for customization:

| Class | Element | |-------|---------| | .hawcx-auth-container | Main container | | .hawcx-form | Form wrapper | | .hawcx-input | Input fields | | .hawcx-button | Buttons | | .hawcx-button-primary | Primary action button | | .hawcx-title | Section headings | | .hawcx-error | Error messages | | .hawcx-method-list | Method selection list | | .hawcx-method-btn | Method button | | .hawcx-loading | Loading indicator | | .hawcx-success | Success message | | .hawcx-qr-container | QR code container | | .hawcx-help-text | Help text |

Type Guards & Helpers

Re-exported from @hawcx/core for convenience:

import {
  // AuthState type guards
  isIdle,
  isLoading,
  isStep,
  isCompleted,
  isError,

  // AuthState getters
  getStepType,
  getMethods,
  getError,

  // Step type guards
  isSelectMethodStep,
  isEnterCodeStep,
  isEnterTotpStep,
  isSetupTotpStep,
  isSetupSmsStep,
  isAwaitApprovalStep,
  isCompletedStep,
  isErrorStep,
} from '@hawcx/react';

TypeScript

All types are exported:

import type {
  AuthState,
  AuthStateStep,
  AuthStateCompleted,
  SessionArtifact,
  HawcxClientConfig,
  HawcxClient,
  AuthStep,
  Method,
  AuthFlowType,
  AuthFlags,
  HawcxSignUpSignInProps,
} from '@hawcx/react';

Requirements

  • React 18+
  • Modern browser with IndexedDB support (for device trust)