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

form-please

v1.12.2

Published

Build forms with ease

Readme

Form, Please

Form, Please turns a Standard Schema and a typed UI definition into a React form. React Hook Form owns state, validation, subscriptions, and array updates. Your controls and slots own the rendered design system.

React 18 and React 19 are supported.

Install

npm install form-please react-hook-form zod

Form, Please accepts any Standard Schema implementation. This example uses Zod.

Create a form

import { nativeFormKit as kit } from "form-please/preset-native"
import { z } from "zod"

const contactSchema = z
	.object({
		email: z.string().email("Enter a valid email"),
	})
	.transform((input) => ({ ...input, normalizedEmail: input.email.trim() }))

const contactForm = kit.defineForm(contactSchema, (ui) => [
	ui.field("email", {
		control: "text",
		label: "Email",
		props: { type: "email" },
	}),
])

export function ContactForm() {
	const form = kit.useForm(contactForm, {
		defaultValues: { email: "" },
		onSubmit({ value }) {
			console.log(value.normalizedEmail)
		},
	})

	return (
		<kit.AutoForm form={form}>
			<kit.Submit>Send</kit.Submit>
		</kit.AutoForm>
	)
}

Render submit content with live typed values and state by passing a function to kit.Submit. The required binding types the values and must match the surrounding form; the button is yours:

<kit.Submit binding={form}>
	{({ buttonProps, values, isDirty, canSubmit }) => (
		<button {...buttonProps} disabled={!canSubmit || !isDirty}>
			Save {values.name}
		</button>
	)}
</kit.Submit>

Reuse a schema-owned group of fields at compatible object paths:

const addressSchema = z.object({
	street: z.string(),
	city: z.string(),
})

const addressFragment = kit.defineFragment(addressSchema, (ui) => [
	ui.field("street", { control: "text", label: "Street" }),
	ui.field("city", { control: "text", label: "City" }),
])

const checkoutSchema = z.object({
	shippingAddress: addressFragment.schema,
	billingAddress: addressFragment.schema,
})

const checkoutForm = kit.defineForm(checkoutSchema, () => [
	addressFragment.fields({ at: "shippingAddress" }),
	addressFragment.fields({ at: "billingAddress" }),
])

Fragment resolvers receive the local fragment input. The host form still owns all state, validation, context, and lifecycle.

Use RHF register, Controller, useWatch, useFormState, useFieldArray, and the unchanged form.api for direct composition. kit.Form supplies FormProvider.

Runtime behavior

  • The Standard Schema validates on submit, then on change after the first submit.
  • The RHF resolver parses the Standard Schema once and returns transformed output while the submit wrapper preserves the schema input snapshot.
  • Ordinary UI resolvers receive the complete deeply readonly schema input and runtime context. They must be synchronous. A selectable field's options may instead be an async function of { values, context, signal }.
  • Fragment resolvers receive their local deeply readonly fragment input and minimum context.
  • Use definition-owned beforeUpdate and afterUpdate for one managed update rule shared by every binding of that definition. Use value middleware and form.update when independent policies or dependent changes must compose atomically. Direct form.api changes bypass both.
  • Hidden fields preserve their values.
  • Array paths use RHF dot notation and rows use stable RHF keys.
  • RHF focuses the first registered invalid field. A focusable error summary is the fallback when no invalid field receives focus.
  • A definition is fixed for the useForm hook lifetime. Use a React key to remount with another definition.

Package entries

| Import | Purpose | | --- | --- | | form-please | Form-kit construction, controls, resources, and shared types | | form-please/default-slots | Accessible structural slots and localization types | | form-please/history | Optional managed value history, navigation, and journal transfer | | form-please/native-controls | Native HTML controls and option types | | form-please/persistence | Optional draft restore, autosave, migration, and storage adapters | | form-please/preset-native | Ready-to-use native form kit | | form-please/preset-mui | Material UI 9 form-kit factory | | form-please/testing | Headless definition inspection and managed update testing | | form-please/layout.css | Optional structural grid and spacing CSS |

The main JavaScript entry does not import CSS.

import "form-please/layout.css"

The Material UI preset requires @mui/material, @emotion/react, and @emotion/styled.

Resources

ResourceState, matchResource, and fromResource map application-owned request state into synchronous form UI. For the common selectable-list case, an async field options function gets dependency tracking and cancellation. Form, Please does not add caching or retries.

Documentation

The physical, typechecked example lives in profile-form.tsx.

Kudos

Kudos to Evgeniy Ivaha for the idea and the example implementation.