Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

@page-speed/forms

Package Overview
Dependencies
Maintainers
2
Versions
64
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@page-speed/forms

Ultra-high-performance React form library with field-level reactivity and tree-shakable architecture

latest
Source
npmnpm
Version
0.8.2
Version published
Maintainers
2
Created
Source

@page-speed/forms

Type-safe, high-performance React form state and input components. Utilized by the OpenSite Semantic UI website platform

Page Speed React Forms


npm version npm downloads License TypeScript Tree-Shakeable

Highlights

  • FormEngine — declarative form component with built-in API integration
  • Field-level reactivity via @legendapp/state/react
  • Built-in input library (text, select, date, time, upload, rich text)
  • Tree-shakable subpath exports (/core, /inputs, /validation, /upload, /integration)
  • Validation rules and utilities (sync + async)
  • Valibot adapter in a separate entrypoint (/validation/valibot)
  • Tailwind token-based default UI aligned with ShadCN interaction patterns

Installation

pnpm add @page-speed/forms
# or
npm install @page-speed/forms

Peer dependencies:

  • react >= 16.8.0
  • react-dom >= 16.8.0

Quick Start with FormEngine

FormEngine is the recommended entry point for most use cases. It provides a declarative API for rendering forms with built-in API integration, validation, file uploads, and styling.

import * as React from "react";
import {
  FormEngine,
  type FormFieldConfig,
} from "@page-speed/forms/integration";

const fields: FormFieldConfig[] = [
  {
    name: "full_name",
    type: "text",
    label: "Full Name",
    required: true,
    placeholder: "Your name",
    columnSpan: 12,
  },
  {
    name: "email",
    type: "email",
    label: "Email",
    required: true,
    placeholder: "you@example.com",
    columnSpan: 6,
  },
  {
    name: "phone",
    type: "tel",
    label: "Phone",
    columnSpan: 6,
  },
  {
    name: "content",
    type: "textarea",
    label: "Message",
    required: true,
    columnSpan: 12,
  },
];

export function ContactForm() {
  return (
    <FormEngine
      api={{
        endpoint: "/api/contact",
        method: "post",
        submissionConfig: { behavior: "showConfirmation" },
      }}
      fields={fields}
      successMessage="Thanks for reaching out!"
      formLayoutSettings={{
        submitButtonSetup: {
          submitLabel: "Send Message",
        },
      }}
    />
  );
}

FormEngine Props

PropTypeDescription
apiPageSpeedFormConfigAPI endpoint and submission configuration
fieldsFormFieldConfig[]Array of field definitions
formLayoutSettingsFormEngineLayoutSettingsLayout, style, and submit button settings
successMessageReactNodeMessage shown after successful submission
onSubmit(values) => void | Promise<void>Custom submit handler
onSuccess(data) => voidCalled after successful submission
onError(error) => voidCalled when submission fails
resetOnSuccessbooleanReset form after success (default: true)

Field Configuration

Each field in the fields array supports:

interface FormFieldConfig {
  name: string;
  type: "text" | "email" | "tel" | "textarea" | "select" | "multiselect" | 
        "date" | "daterange" | "time" | "file" | "checkbox" | "radio";
  label?: string;
  placeholder?: string;
  required?: boolean;
  columnSpan?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
  className?: string;
  options?: { label: string; value: string }[]; // For select/multiselect/radio
  // File-specific props
  accept?: string;
  maxFiles?: number;
  maxFileSize?: number;
}

Layout Options

Standard Layout (default)

Multi-column grid with a submit button below the fields:

<FormEngine
  fields={fields}
  formLayoutSettings={{
    formLayout: "standard",
    submitButtonSetup: {
      submitLabel: "Submit",
      submitVariant: "default", // | "destructive" | "outline" | "secondary" | "ghost" | "link"
    },
    styleRules: {
      formContainer: "max-w-2xl mx-auto",
      fieldsContainer: "gap-6",
      formClassName: "space-y-4",
    },
  }}
/>

Button-Group Layout

Inline input with submit button (e.g., newsletter signup):

<FormEngine
  fields={[{ name: "email", type: "email", label: "Email", required: true }]}
  formLayoutSettings={{
    formLayout: "button-group",
    buttonGroupSetup: {
      size: "lg", // | "xs" | "sm" | "default"
      submitLabel: "Subscribe",
      submitVariant: "default",
    },
  }}
/>

Using formEngineSetup Wrapper

For block/component libraries that provide default configurations:

import {
  FormEngine,
  type FormEngineSetup,
  type FormFieldConfig,
  type FormEngineStyleRules,
} from "@page-speed/forms/integration";

const defaultFields: FormFieldConfig[] = [
  { name: "email", type: "email", label: "Email", required: true },
];

const defaultStyleRules: FormEngineStyleRules = {
  formClassName: "space-y-6",
};

// Consumer passes setup, component provides defaults
function ContactBlock({ formEngineSetup }: { formEngineSetup?: FormEngineSetup }) {
  return (
    <FormEngine
      formEngineSetup={formEngineSetup}
      defaultFields={defaultFields}
      defaultStyleRules={defaultStyleRules}
    />
  );
}

Package Entry Points

Main

  • @page-speed/forms

Exports:

  • useForm, useField, Form, Field, FormContext
  • Core form/types interfaces
  • @page-speed/forms/integration

Exports:

  • FormEngine, FormEngineSetup, FormEngineProps
  • FormFieldConfig, FormEngineStyleRules, FormEngineLayoutSettings
  • DynamicFormField, useContactForm, useFileUpload

Inputs

  • @page-speed/forms/inputs

Exports:

  • TextInput, TextArea, Checkbox, CheckboxGroup, Radio
  • Select, MultiSelect, DatePicker, DateRangePicker, TimePicker
  • FileInput

Validation

  • @page-speed/forms/validation
  • @page-speed/forms/validation/rules
  • @page-speed/forms/validation/utils
  • @page-speed/forms/validation/valibot

Upload

  • @page-speed/forms/upload

Input Notes

TimePicker

TimePicker uses a native input[type="time"] UX internally.

  • Accepts controlled values in HH:mm (24-hour) or h:mm AM/PM (12-hour)
  • Emits HH:mm when use24Hour is true
  • Emits h:mm AM/PM when use24Hour is false

DatePicker and DateRangePicker

  • Calendar popovers close on outside click
  • Compact month/day layout using tokenized Tailwind classes
  • DateRangePicker renders two months and highlights endpoints + in-range dates

Select and MultiSelect

  • Close on outside click
  • Search support
  • Option groups
  • Selected options inside the menu use accent highlight styles

Styling (Tailwind 4 + Semantic Tokens)

This library ships with Tailwind utility classes and semantic token class names.

Base conventions

  • Inputs/triggers are transparent shells with semantic borders/rings
  • Fields with values (text-like controls) use ring-2 ring-primary
  • Error states use destructive border/ring
  • Dropdown selected rows use muted backgrounds

FormEngine Style Rules

interface FormEngineStyleRules {
  formContainer?: string;       // Wrapper around <form>
  fieldsContainer?: string;     // Grid wrapper for fields
  fieldClassName?: string;      // Fallback className for fields
  formClassName?: string;       // Applied to <form> element
  successMessageClassName?: string;
  errorMessageClassName?: string;
}

Autofill normalization

Text-like controls apply autofill reset classes to avoid browser-injected background/text colors breaking your theme contrast.

See INPUT_AUTOFILL_RESET_CLASSES in src/utils.ts.

Token requirements

Ensure your app defines semantic tokens used in classes such as:

  • background, foreground, border, input, ring
  • primary, primary-foreground
  • muted, muted-foreground
  • destructive, destructive-foreground
  • popover, popover-foreground
  • card, card-foreground

For complete styling guidance, see docs/STYLES.md.

Advanced: Low-Level APIs

For custom form implementations, the lower-level useForm, Form, and Field APIs are available:

import { Form, Field, useForm } from "@page-speed/forms";
import { TextInput } from "@page-speed/forms/inputs";

function CustomForm() {
  const form = useForm({
    initialValues: { email: "" },
    validationSchema: {
      email: (value) => (!value ? "Required" : undefined),
    },
    onSubmit: async (values) => {
      console.log(values);
    },
  });

  return (
    <Form form={form}>
      <Field name="email" label="Email">
        {({ field, meta }) => (
          <TextInput
            {...field}
            error={Boolean(meta.touched && meta.error)}
          />
        )}
      </Field>
      <button type="submit">Submit</button>
    </Form>
  );
}

Validation Utilities

Use built-in rules:

  • required, email, url, phone
  • minLength, maxLength, min, max
  • pattern, matches, oneOf
  • creditCard, postalCode, alpha, alphanumeric, numeric, integer
  • compose

Use utilities from /validation/utils:

  • debounce, asyncValidator, crossFieldValidator, when
  • setErrorMessages, getErrorMessage, resetErrorMessages

File Uploads

FileInput and FormEngine support validation, drag/drop, preview, and crop workflows.

For full two-phase upload patterns and serializer usage, see:

Development

pnpm test:ci
pnpm build
pnpm type-check

License

MIT. See LICENSE.

Keywords

react

FAQs

Package last updated on 04 Mar 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts