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

@multiplatform.one/forms

v6.1.0

Published

Cross-platform form components with URL state management

Readme

@multiplatform.one/forms

Cross-platform form components with URL state management for multiplatform.one applications.

Features

  • 🔄 URL State Sync: Automatically sync form state with URL parameters
  • 📱 Cross-Platform: Works on web, iOS, and Android
  • 🎨 Tamagui Components: Beautiful, themeable form components
  • 🏗️ TanStack Form: Powerful form state management
  • 🔍 SSR Support: Server-side rendering with proper hydration
  • 📝 TypeScript: Full type safety

Installation

npm install @multiplatform.one/forms
# or
yarn add @multiplatform.one/forms
# or
pnpm add @multiplatform.one/forms

Basic Usage

import { Form, Input, Checkbox, Button } from "@multiplatform.one/forms";

function MyForm() {
  return (
    <Form
      syncWithUrl={true}
      urlDebounceMs={500}
      onSubmit={async (values) => {
        console.log("Form submitted:", values);
      }}
    >
      <Input
        name="email"
        label="Email"
        validators={{
          onChange: ({ value }) => (!value?.includes("@") ? "Invalid email" : undefined),
        }}
      />

      <Input name="password" label="Password" type="password" />

      <Checkbox name="remember" label="Remember me" />

      <Button type="submit">Sign In</Button>
    </Form>
  );
}

URL State Synchronization

Enable automatic URL state synchronization to create shareable form states:

<Form
  syncWithUrl={true}
  urlDebounceMs={500}
  formOptions={{
    defaultValues: {
      search: "",
      category: "all",
      sortBy: "date",
    },
  }}
>
  {/* Form fields */}
</Form>

This will automatically sync form values to the URL:

?search=hello&category=tech&sortBy=date

Advanced Usage with TanStack Form

import { useForm, Form, Input } from "@multiplatform.one/forms";

function AdvancedForm() {
  const form = useForm({
    defaultValues: {
      name: "",
      age: 0,
    },
    validators: {
      onChange: ({ value }) => {
        if (value.age < 0) {
          return "Age must be positive";
        }
      },
    },
  });

  return (
    <Form form={form} syncWithUrl={true}>
      <Input
        name="name"
        label="Name"
        validators={{
          onChange: ({ value }) => ((value?.length ?? 0) < 3 ? "Name too short" : undefined),
        }}
      />

      <Input name="age" label="Age" type="number" />

      <Button type="submit" />
    </Form>
  );
}

SSR Support

The forms work seamlessly with server-side rendering:

// Server-side: Forms pre-populate from URL
// Client-side: Hydration preserves user input

function SSRForm() {
  return (
    <Form syncWithUrl={true}>
      <Input
        name="search"
        label="Search"
        defaultValue="" // SSR-safe default
      />
    </Form>
  );
}

ChildTable form binding

The ChildTable component lives in @multiplatform.one/table (it composes TableInput with FieldLayout from this package). Import it from @multiplatform.one/table, not from @multiplatform.one/forms.

ChildTable works as a first-class form field when used inside <Form>:

<Form formOptions={{ defaultValues: { items: [] } }}>
  <ChildTable
    name="items"
    columns={[
      { accessorKey: "item_code", header: "Item Code" },
      { accessorKey: "qty", header: "Qty" },
    ]}
    defaultRow={{ idx: 0, item_code: "", qty: 1 }}
  />
</Form>
  • form.getFieldValue("items") returns the array
  • Add/delete updates form state
  • Per-column linkResolver for cell-level links (e.g. item_code → /items/[id])

readOnly vs disabled

| Aspect | readOnly | disabled | | ---------- | --------------- | --------------- | | Editable | No | No | | Submitted | Yes | Typically no | | Appearance | Normal | Grayed out | | A11y | aria-readonly | aria-disabled |

All fields support readOnly. Use when the value should be visible and submitted but not editable.

Link behavior (linkResolver)

Optional link rendering when displaying values:

  • Field-level: linkResolver?: (value) => Href | null on Input (and similar)
  • ChildTable column-level: linkResolver?: (value, row, rowIndex) => Href | null on columns

When linkResolver returns a non-null href, the value renders as <Link href={...}>. In edit mode, normal input is shown. Link behavior applies in readOnly/display mode.

Frappe: Schema mapping (doctype → linkResolver) belongs in public/frappe-ui wrappers. Core forms stay doctype-agnostic.

Package Structure

src/
├── index.ts              # Public exports
├── form/                 # Form wrapper, context
├── fields/               # Field components
│   ├── datePicker/       # DatePicker, MultiDatePicker, DateRangePicker, Calendar
│   ├── colorPicker/
│   └── ...
├── childTable/           # Repeatable row table (form-integrated)
├── fieldLayout.tsx       # Label, error, helper text layout
└── utils/LinkCell.tsx    # Link wrapper for linkResolver

Components

Form

Main form wrapper that provides context and handles submission.

Input

Text input field with validation support.

Checkbox

Checkbox input with label.

Select

Dropdown selection field.

Button

Form submission button; use type="submit" for form submission.

Hooks

useFormContext

Access the form instance from child components.

useUrlState

Sync any state with URL parameters (re-exported from router).

useSearchParams

Read and write URL search parameters (re-exported from router).

License

Apache-2.0