Skip to content
Form, Please

Shadcn with Valibot

This example keeps the design-system boundary in the application. A local kit maps "Form, Please" control props and slots to shadcn-style components. Valibot provides the Standard Schema.

Install the adapter

npx shadcn@latest add r13v/form-please/shadcn-form-kit

The registry item installs form-please and copies the adapter into your application. Install the schema library used by your form separately. This example uses valibot.

npm install valibot

The item targets shadcn's Base UI implementation. Review the copied component imports when your project uses another style or customized component props. The adapter remains normal application source, so it can follow local aliases, styles, and signatures.

Try the workshop proposal

Change radio and switch values, move the sliders, search the comboboxes, choose calendar values, and edit the OTP. Submit to run the Valibot schema twice and receive transformed output.

Workshop proposal

Native controls rendered with local shadcn primitives.

Session experience

Base UI option controls and each slider value shape.

One numeric value, in minutes.

A fixed two-number tuple.

An arbitrary array of numeric thumbs.

Discovery and schedule

Searchable options, calendar values, and OTP input.

1
0
4
7
2
9
Submit the proposal to validate it with Valibot.

Adapter surface

The local adapter defines native-shaped controls, Base UI option controls, sliders, date pickers, comboboxes, an OTP control, and structural slots. Each control uses the public ControlProps contract. The kit uses the public createFormKit and defineControl functions. Its radio and combobox option types mark their IDs with OptionValue<string>, so Valibot picklist fields reject option values outside their inferred unions.

Copy the example

"use client"
 
import type { ,  } from "form-please"
import {  } from "react"
import * as  from "valibot"
 
import {  as  } from "../components/ui/form-please/shadcn-form-kit"
 
const  = .({
	: .(.(), .(3, "Use at least three characters")),
	: .(
		.(),
		.(20, "Explain the workshop in at least 20 characters"),
	),
	: .(["design", "engineering", "leadership"]),
	: .(.(), .(6), .(80)),
	: .(),
	: .(),
	: .(),
	: .(.()),
	: .(["studio", "remote", "hybrid"]),
	: .(),
	: .(.(), .(30), .(180)),
	: .([.(), .()]),
	: .(.()),
	: .(),
	: .(.()),
	: .(),
	: .({
		: .(.()),
		: .(.()),
	}),
	: .(
		.(),
		.(/^\d{6}$/, "Enter the six-digit invite code"),
	),
})
 
type  = <typeof >
type  = <typeof >
 
const  = {
	: [
		{ : "design", : "Design" },
		{ : "engineering", : "Engineering" },
		{ : "leadership", : "Leadership" },
	],
	: [
		{
			: "studio",
			: "Studio",
			: "A facilitated, in-person room.",
		},
		{
			: "remote",
			: "Remote",
			: "A live online session.",
		},
		{
			: "hybrid",
			: "Hybrid",
			: "One room with remote participants.",
		},
	],
	: [
		{ : "north-studio", : "North studio" },
		{ : "library-lab", : "Library lab" },
		{ : "remote-room", : "Remote room" },
	],
	: [
		{ : "research", : "Research" },
		{ : "prototyping", : "Prototyping" },
		{ : "facilitation", : "Facilitation" },
		{ : "systems", : "Systems thinking" },
	],
} as 
 
const  = .(, {
	: [
		{
			: "section",
			: "proposal",
			: "Workshop proposal",
			: "Native controls rendered with local shadcn primitives.",
			: 2,
			: [
				{
					: "field",
					: "title",
					: "text",
					: "Title",
					: true,
					: { : "Designing useful constraints" },
				},
				{
					: "field",
					: "track",
					: "select",
					: "Track",
					: .,
				},
				{
					: "field",
					: "abstract",
					: "textarea",
					: "Abstract",
					: true,
					: { : 4 },
				},
				{
					: "field",
					: "capacity",
					: "number",
					: "Capacity",
					: { : 6, : 80, : 1 },
				},
				{
					: "field",
					: "proposalDate",
					: "date",
					: "Proposal date",
				},
				{
					: "field",
					: "startsAt",
					: "time",
					: "Preferred start time",
					: { : 900 },
				},
				{
					: "field",
					: "accessibilityReview",
					: "checkbox",
					: "Request an accessibility review",
				},
				{
					: "field",
					: "brief",
					: "file",
					: "Optional brief",
					: { : ".pdf,.md,text/markdown,application/pdf" },
				},
			],
		},
		{
			: "section",
			: "experience",
			: "Session experience",
			: "Base UI option controls and each slider value shape.",
			: 2,
			: [
				{
					: "field",
					: "format",
					: "radio",
					: "Format",
					: .,
				},
				{
					: "field",
					: "recordingAllowed",
					: "switch",
					: "Allow a recording",
					: { : "sm" },
				},
				{
					: "field",
					: "duration",
					: "slider",
					: "Duration",
					: "One numeric value, in minutes.",
					: {
						: 30,
						: 180,
						: 15,
						: { : "unit", : "minute" },
					},
				},
				{
					: "field",
					: "audienceRange",
					: "rangeSlider",
					: "Audience experience range",
					: "A fixed two-number tuple.",
					: { : 0, : 10, : 1, : 2 },
				},
				{
					: "field",
					: "agendaCheckpoints",
					: "multiSlider",
					: "Agenda checkpoints",
					: "An arbitrary array of numeric thumbs.",
					: { : 0, : 100, : 5 },
				},
			],
		},
		{
			: "section",
			: "schedule",
			: "Discovery and schedule",
			: "Searchable options, calendar values, and OTP input.",
			: 2,
			: [
				{
					: "field",
					: "venue",
					: "combobox",
					: "Venue",
					: .,
					: {
						: "Search venues",
						: true,
					},
				},
				{
					: "field",
					: "topics",
					: "multiCombobox",
					: "Topics",
					: .,
					: {
						: "Add topics",
					},
				},
				{
					: "field",
					: "workshopDate",
					: "datePicker",
					: "Workshop date",
					: {
						: "Pick a date",
						: "dropdown",
						: [
							{ : "2027-04-09", : "Spring lab" },
							{ : "2027-09-17", : "Autumn lab" },
						],
					},
				},
				{
					: "field",
					: "availability",
					: "dateRangePicker",
					: "Travel availability",
					: { : 2 },
				},
				{
					: "field",
					: "inviteCode",
					: "inputOtp",
					: "Invite code",
					: true,
					: {
						: 6,
						: [3, 3],
						: true,
						: "^\\d*$",
						: "one-time-code",
					},
				},
			],
		},
	],
})
 
const  = {
	: "Designing useful constraints",
	:
		"A practical session for turning product constraints into focused experiments.",
	: "design",
	: 24,
	: "2026-08-02",
	: "10:00",
	: true,
	: ,
	: "studio",
	: false,
	: 90,
	: [2, 7],
	: [20, 50, 80],
	: "north-studio",
	: ["research", "prototyping"],
	: "2027-04-09",
	: { : "2027-04-07", : "2027-04-11" },
	: "104729",
} satisfies 
 
export function () {
	const [, ] = <>()
	const  = .(, {
		,
		({  }) {
			()
		},
	})
	let  = "Submit the proposal to validate it with Valibot."
	if ( !== ) {
		 = `${.} is ready for ${.} participants.`
	}
 
	return (
		<
			="Shadcn with Valibot workshop example"
			="grid gap-4"
		>
			<. ="grid gap-4" ={}>
				<.>Submit proposal</.>
			</.>
			< ="polite" ="text-sm text-muted-foreground">
				{}
			</>
		</>
	)
}

Read Form kits for the control and slot contracts. Review the registry manifest and adapter source before adapting them to your project. Append a matching Git release tag to the registry item reference, such as #vX.Y.Z, when an installation must be reproducible.