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

@logic-joe/logicforms-react

v0.0.35

Published

React component wrapper for LogicForms - lightweight form embedding

Readme

@logic-joe/logicforms-react

npm version License: MIT

React components for embedding LogicForms. Features Zod validation, React Hook Form integration, file uploads, localization, and full customization support.

Installation

npm install @logic-joe/logicforms-react
# or
pnpm add @logic-joe/logicforms-react
# or
yarn add @logic-joe/logicforms-react

Peer Dependencies: React 18+ or 19+

Quick Start

import { Form } from "@logic-joe/logicforms-react";

function App() {
  return (
    <Form
      formId="your-form-id"
      baseUrl="https://logicforms.onrender.com"
      onSubmit={(data) => console.log("Submitted:", data)}
      onError={(error) => console.error("Error:", error)}
    />
  );
}

Form Component Props

interface FormProps {
  // Required
  formId: string;

  // Configuration
  baseUrl?: string; // Default: "https://logicforms.onrender.com"
  className?: string; // Additional CSS class
  theme?: "light" | "dark" | "system"; // Default: "light"

  // Localization
  locale?: string; // Explicit locale (e.g., "de", "fr")
  autoDetectLocale?: boolean; // Auto-detect from browser (default: true)
  onLocaleChange?: (locale: string, availableLocales: string[]) => void;

  // Callbacks
  onSubmit?: (data: Record<string, string>) => void;
  onError?: (error: Error) => void;

  // Cookie consent
  cookiesAccepted?: boolean; // When false, blocks third-party scripts and shows overlay
  onRequestCookieConsent?: () => void; // Called when user clicks consent button

  // Preview mode (for editor integration)
  previewMode?: boolean;
  previewData?: PreviewModeData;
  forceValidation?: boolean;
  hidePreviewBanner?: boolean;

  // Custom renderers (see Custom Rendering section)
  renderInput?: RenderInputFn;
  renderTextarea?: RenderTextareaFn;
  renderSelect?: RenderSelectFn;
  // ... and more
}

Custom UI with useMaxForm Hook

For full control over form rendering, use the useMaxForm hook:

import { useMaxForm } from "@logic-joe/logicforms-react";

function CustomForm() {
  const {
    form, // React Hook Form instance
    fields, // Form field definitions
    layout, // Layout blocks
    settings, // Form settings
    isLoading,
    isSubmitting,
    isSuccess,
    error,
    submitForm,
    resetForm,
    getFieldError,
    getFieldById,
  } = useMaxForm({
    formId: "your-form-id",
    baseUrl: "https://logicforms.onrender.com",
    mode: "onBlur", // Validation mode
  });

  if (isLoading) return <div>Loading...</div>;
  if (isSuccess) return <div>{settings.successMessage}</div>;

  return (
    <form onSubmit={form.handleSubmit(submitForm)}>
      {fields.map((field) => (
        <div key={field.id}>
          <label>{field.label}</label>
          <input {...form.register(field.name)} />
          {getFieldError(field.name) && (
            <span className="error">{getFieldError(field.name)}</span>
          )}
        </div>
      ))}
      <button type="submit" disabled={isSubmitting}>
        {settings.submitButtonText}
      </button>
    </form>
  );
}

File Upload

The FileUpload component handles the complete upload flow including virus scanning:

import { FileUpload } from "@logic-joe/logicforms-react";

function FileField({ field, formId }) {
  const [fileId, setFileId] = useState("");

  return (
    <FileUpload
      field={field}
      formId={formId}
      baseUrl="https://logicforms.onrender.com"
      value={fileId}
      onChange={setFileId}
    />
  );
}

The component automatically:

  1. Gets a presigned upload URL
  2. Uploads to the quarantine bucket
  3. Triggers antivirus scanning
  4. Polls for scan completion
  5. Shows upload progress and status

Localization

Forms support multiple languages with automatic browser detection:

// Auto-detect browser locale (default behavior)
<Form formId="abc" autoDetectLocale={true} />

// Explicit locale
<Form formId="abc" locale="de" />

// React to locale changes
<Form
  formId="abc"
  onLocaleChange={(locale, availableLocales) => {
    console.log("Current:", locale);
    console.log("Available:", availableLocales);
  }}
/>

useFormLocale Hook

For building custom locale selectors:

import { useFormLocale } from "@logic-joe/logicforms-react";

function LocaleSelector() {
  const { locale, setLocale, availableLocales, isLoading } = useFormLocale({
    formId: "your-form-id",
    baseUrl: "https://logicforms.onrender.com",
  });

  return (
    <select value={locale} onChange={(e) => setLocale(e.target.value)}>
      {availableLocales.map((loc) => (
        <option key={loc} value={loc}>
          {loc}
        </option>
      ))}
    </select>
  );
}

CAPTCHA Integration

Google reCAPTCHA

Configure reCAPTCHA in your form settings (dashboard). The component handles v2 and v3 automatically:

// reCAPTCHA is automatically rendered when enabled in form settings
<Form formId="abc" />

Cloudflare Turnstile

Similarly configured via form settings:

// Turnstile widget rendered automatically when enabled
<Form formId="abc" />

Theming

Theme Mode

// Light theme (default)
<Form formId="abc" theme="light" />

// Dark theme
<Form formId="abc" theme="dark" />

// Follow system preference
<Form formId="abc" theme="system" />

Custom Theme Colors

Theme colors can be configured in the form settings (dashboard). The component automatically applies them:

interface ThemeColors {
  primary?: string;
  primaryForeground?: string;
  background?: string;
  foreground?: string;
  muted?: string;
  mutedForeground?: string;
  border?: string;
  input?: string;
  destructive?: string;
}

Custom CSS

Forms support custom CSS defined in the dashboard. The CSS is automatically scoped to the form:

/* Example custom CSS (defined in dashboard) */
.logicforms-{formId} input {
  border-radius: 8px;
}

Custom Rendering

Override any part of the form with custom render functions:

Field Renderers

<Form
  formId="abc"
  renderInput={(ctx) => (
    <input
      {...ctx.register(ctx.name)}
      placeholder={ctx.field.placeholder}
      className={ctx.error ? "error" : ""}
    />
  )}
  renderTextarea={(ctx) => <textarea {...ctx.register(ctx.name)} rows={6} />}
  renderSelect={(ctx) => (
    <select value={ctx.value} onChange={(e) => ctx.onChange(e.target.value)}>
      {ctx.field.options.map((opt) => (
        <option key={opt.value} value={opt.value}>
          {opt.label}
        </option>
      ))}
    </select>
  )}
/>

Field Render Context

interface FieldRenderContext {
  field: FormField; // Field definition
  register: UseFormRegister; // React Hook Form register
  error?: FieldError; // Validation error
  value: string; // Current value
  onChange: (value: string) => void;
  onBlur: () => void;
  name: string;
  disabled?: boolean;
}

Layout Block Renderers

<Form
  formId="abc"
  renderHeading={(block) => <h2 style={{ color: "blue" }}>{block.content}</h2>}
  renderTextBlock={(block) => <p className="custom-text">{block.content}</p>}
  renderDivider={() => <hr className="my-divider" />}
  renderRow={(block, children) => <div className="custom-row">{children}</div>}
/>

State Renderers

<Form
  formId="abc"
  renderLoading={() => <Spinner />}
  renderSuccess={(message) => <div className="success-banner">{message}</div>}
  renderFormError={(error) => <div className="error-alert">{error}</div>}
  renderFieldError={(error) => (
    <span className="field-error">{error.message}</span>
  )}
  renderSubmit={({ isSubmitting, buttonText, hasErrors }) => (
    <button type="submit" disabled={isSubmitting || hasErrors}>
      {isSubmitting ? "Sending..." : buttonText}
    </button>
  )}
  renderFieldWrapper={(field, children, error) => (
    <div className={`field-group ${error ? "has-error" : ""}`}>{children}</div>
  )}
/>

Cookie Consent

If your form uses third-party services (GA4, reCAPTCHA, Turnstile), you need user consent before loading their scripts (GDPR/ePrivacy). Use cookiesAccepted to control this:

import { useState } from "react";
import { Form } from "@logic-joe/logicforms-react";

function MyForm() {
  const [cookiesAccepted, setCookiesAccepted] = useState(false);

  return (
    <Form
      formId="your-form-id"
      cookiesAccepted={cookiesAccepted}
      onRequestCookieConsent={() => {
        // Open your cookie banner/dialog
        myCookieBanner.show();
      }}
    />
  );

  // Later, when user accepts: setCookiesAccepted(true)
}

When cookiesAccepted is false, the form is blurred and a localized consent overlay is shown. First-party analytics (self-hosted, no cookies) continue to work. Omitting cookiesAccepted preserves backwards compatibility — all scripts load normally.

Analytics (Google Analytics 4)

When enabled in form settings, the component automatically tracks:

  • form_view - Form loaded
  • form_start - First field interaction
  • form_submit - Successful submission
  • form_error - Submission error

useAnalytics Hook

For custom analytics implementations:

import { useAnalytics } from "@logic-joe/logicforms-react";

const { trackFormView, trackFormStart, trackFormSubmit, trackFormError } =
  useAnalytics({
    measurementId: "G-XXXXXXXXXX",
    formId: "your-form-id",
    formName: "Contact Form",
  });

Validation Utilities

Build custom validation schemas:

import {
  buildFieldSchema,
  buildFormSchema,
  validateFormData,
} from "@logic-joe/logicforms-react";
import type { FormField } from "@logic-joe/logicforms-api";

// Build schema for a single field
const fieldSchema = buildFieldSchema(field);

// Build schema for entire form
const formSchema = buildFormSchema(fields);

// Validate data
const result = validateFormData(formSchema, data);

Block Components

For custom layouts, use the exported block components:

import {
  HeadingBlock,
  TextBlock,
  DividerBlock,
  RowBlock,
} from "@logic-joe/logicforms-react";

<HeadingBlock block={{ content: "Title", level: 2 }} />
<TextBlock block={{ content: "Description text" }} />
<DividerBlock />
<RowBlock block={rowBlock} renderChild={renderBlock} />

TypeScript Support

Full TypeScript support with exported types:

import type {
  FormProps,
  FormData,
  FormSettingsData,
  ThemeMode,
  FieldRenderContext,
  FileFieldRenderContext,
  RenderInputFn,
  RenderTextareaFn,
  RenderSelectFn,
  RenderCheckboxFn,
  RenderRadioFn,
  RenderFileFn,
  RenderHeadingFn,
  RenderSubmitFn,
  SubmitRenderProps,
  UseMaxFormOptions,
  UseMaxFormReturn,
  UseFormLocaleOptions,
  UseFormLocaleReturn,
  UseAnalyticsOptions,
} from "@logic-joe/logicforms-react";

UMD Build

For non-bundler usage, a UMD build is available:

<script src="https://unpkg.com/@logic-joe/logicforms-react"></script>
<script>
  const { Form, useMaxForm, render } = window.LogicForms;

  // Or use the render helper
  LogicForms.render("#form-container", {
    formId: "your-form-id",
    baseUrl: "https://logicforms.onrender.com",
  });
</script>

License

MIT