Skip to content
Form, Please

Membership ladder

Four named tiers each contain a movable benefit array. The schema requires the discount values to increase across the tier ladder.

Try the complete flow

Change the discount values to test cross-tier validation. Add and move benefits inside each tier. Connect the selected workspace, then add a pause window with an application-owned shortcut.

Loading membership ladder…

What this form demonstrates

  • Four nested arrays under fixed object paths.
  • Cross-tier schema validation.
  • Query-provided workspace options through form context.
  • form.api.setValue for connection state.
  • form.api.getValues and form.api.setValue for pause shortcuts.
  • A live ladder preview through useWatch.

Copy the source

"use client"
 
import {
	,
	,
	,
	,
} from "@tanstack/react-query"
import {
	,
	type ,
	type ,
	type ,
	type ,
} from "form-please"
import {  } from "form-please/default-slots"
import {  } from "form-please/native-controls"
import {  } from "react"
import {  } from "zod"
 
const  = .({
	: .().(2, "Describe the benefit"),
	: .().().(0),
})
 
const  = .({
	: .().(0).(80),
	: .().(1, "Add at least one benefit"),
})
 
const  = 
	.({
		: .().(4, "Name the membership program"),
		: .(["monthly", "quarterly", "annual"]),
		: .().(1, "Choose a workspace"),
		: .({
			: .(),
			: .(),
		}),
		: .({
			: ,
			: ,
			: ,
			: ,
		}),
		: .(
			.({
				: .().(1, "Choose a start date"),
				: .().(1, "Choose an end date"),
				: .().(3, "Explain the pause"),
			}),
		),
	})
	.((, ) => {
		const  = [
			...,
			...,
			...,
			...,
		]
		for (let  = 1;  < .;  += 1) {
			if (([] ?? 0) < ([ - 1] ?? 0)) {
				.({
					: "custom",
					: ["tiers"],
					: "Higher tiers cannot offer a smaller reduction",
				})
				break
			}
		}
		for (const [, ] of ..()) {
			if (. < .) {
				.({
					: "custom",
					: ["pauseWindows", , "endsOn"],
					: "The pause must end after it starts",
				})
			}
		}
	})
	.(() => ({
		...,
		: .(.).(
			(, ) =>  + ..,
			0,
		),
	}))
 
type  = <typeof >
type  = <typeof >
type  = {
	readonly : readonly {
		readonly : string
		readonly : string
	}[]
}
 
const  = {
	: "Common Ground Membership",
	: "monthly",
	: "commons-hub",
	: { : false, : true },
	: {
		: {
			: 0,
			: [{ : "Monthly community digest", : 1 }],
		},
		: {
			: 8,
			: [{ : "Open desk sessions", : 2 }],
		},
		: {
			: 15,
			: [{ : "Project consultations", : 1 }],
		},
		: {
			: 22,
			: [{ : "Private program previews", : 4 }],
		},
	},
	: [
		{
			: "2027-08-01",
			: "2027-08-14",
			: "Annual maintenance",
		},
	],
} satisfies 
 
const  = ({
	: (),
	: (),
})
const  = .<>()
type  = <typeof , >
 
function ({
	,
	,
}: {
	readonly : 
	readonly : number
}) {
	const  = (: ["pauseWindows"][number]) => {
		..(
			"pauseWindows",
			[.....("pauseWindows"), ],
			{ : true },
		)
	}
	return (
		<
			="form-please-complex__embedded"
			="Pause calendar shortcuts"
		>
			<>Calendar shortcuts</>
			< ="form-please-complex__choice-list">
				<
					={() =>
						({
							: "2027-12-24",
							: "2027-12-31",
							: "Winter closure",
						})
					}
					="button"
				>
					Add winter closure
				</>
				<
					={() =>
						({
							: "2028-04-10",
							: "2028-04-12",
							: "System migration",
						})
					}
					="button"
				>
					Add migration window
				</>
				<>{} pause window(s) scheduled</>
			</>
		</>
	)
}
 
function ({
	,
	,
	,
}: {
	readonly : 
	readonly : string
	readonly : boolean
}) {
	const  = ({
		: (: boolean) =>
			({ , :  }, 360),
	})
	let  = "Workspace disconnected"
	let  = "Connect"
	if () {
		 = "Workspace connected"
		 = "Disconnect"
	}
	if (.)  = "Updating connection…"
 
	return (
		<
			="form-please-complex__embedded"
			="Workspace connection"
		>
			<>{}</>
			<
				={.}
				={async () => {
					const  = await .(!)
					..("connection.enabled", .)
				}}
				="button"
			>
				{}
			</>
		</>
	)
}
 
const  = .(, {
	: [
		{
			: "section",
			: "program",
			: "Membership program",
			: 2,
			: [
				{
					: "field",
					: "programName",
					: "text",
					: "Program name",
				},
				{
					: "field",
					: "billingCycle",
					: "select",
					: "Billing cycle",
					: [
						{ : "monthly", : "Monthly" },
						{ : "quarterly", : "Quarterly" },
						{ : "annual", : "Annual" },
					],
				},
				{
					: "field",
					: "workspaceId",
					: "select",
					: "Member workspace",
					: ({  }) => .,
				},
				{
					: "field",
					: "connection.syncExistingMembers",
					: "checkbox",
					: "Sync existing members",
				},
			],
		},
		...(),
		{
			: "array",
			: "pauseWindows",
			: "Pause windows",
			:
				"Dates can be entered directly or added from calendar shortcuts.",
			: { : "", : "", : "" },
			: [
				{ : "field", : "startsOn", : "date", : "Starts" },
				{ : "field", : "endsOn", : "date", : "Ends" },
				{ : "field", : "reason", : "text", : "Reason" },
			],
		},
	],
})
 
function () {
	return [
		{
			: "section",
			: "tier-seed",
			: "Seed tier",
			: [
				{
					: "field",
					: "tiers.seed.discountPercent",
					: "number",
					: "Reduction percent",
					: { : 0, : 80, : 1 },
				},
				{
					: "array",
					: "tiers.seed.benefits",
					: "Benefits",
					: { : "", : 0 },
					: [
						{
							: "field",
							: "label",
							: "text",
							: "Benefit",
						},
						{
							: "field",
							: "monthlyLimit",
							: "number",
							: "Monthly limit",
							: { : 0, : 1 },
						},
					],
				},
			],
		},
		{
			: "section",
			: "tier-sprout",
			: "Sprout tier",
			: [
				{
					: "field",
					: "tiers.sprout.discountPercent",
					: "number",
					: "Reduction percent",
					: { : 0, : 80, : 1 },
				},
				{
					: "array",
					: "tiers.sprout.benefits",
					: "Benefits",
					: { : "", : 0 },
					: [
						{ : "field", : "label", : "text", : "Benefit" },
						{
							: "field",
							: "monthlyLimit",
							: "number",
							: "Monthly limit",
							: { : 0, : 1 },
						},
					],
				},
			],
		},
		{
			: "section",
			: "tier-canopy",
			: "Canopy tier",
			: [
				{
					: "field",
					: "tiers.canopy.discountPercent",
					: "number",
					: "Reduction percent",
					: { : 0, : 80, : 1 },
				},
				{
					: "array",
					: "tiers.canopy.benefits",
					: "Benefits",
					: { : "", : 0 },
					: [
						{ : "field", : "label", : "text", : "Benefit" },
						{
							: "field",
							: "monthlyLimit",
							: "number",
							: "Monthly limit",
							: { : 0, : 1 },
						},
					],
				},
			],
		},
		{
			: "section",
			: "tier-founder",
			: "Founder tier",
			: [
				{
					: "field",
					: "tiers.founder.discountPercent",
					: "number",
					: "Reduction percent",
					: { : 0, : 80, : 1 },
				},
				{
					: "array",
					: "tiers.founder.benefits",
					: "Benefits",
					: { : "", : 0 },
					: [
						{ : "field", : "label", : "text", : "Benefit" },
						{
							: "field",
							: "monthlyLimit",
							: "number",
							: "Monthly limit",
							: { : 0, : 1 },
						},
					],
				},
			],
		},
	] satisfies readonly <
		,
		typeof .,
		
	>[]
}
 
export function () {
	const [] = (
		() => new ({ : { : { : false } } }),
	)
	return (
		< ={}>
			< />
		</>
	)
}
 
function () {
	const  = ({
		: ["membership-draft"],
		: () => (, 380),
	})
	const  = ({
		: ["member-workspaces"],
		: () =>
			(
				[
					{ : "commons-hub", : "Commons Hub" },
					{ : "field-notes", : "Field Notes Circle" },
					{ : "makers-union", : "Makers Union" },
				],
				460,
			),
	})
	const  = ({
		: (: ) =>
			({ : . + 500 }, 440),
	})
	const [, ] = ("Membership draft loaded.")
	const  = .(, {
		: ,
		: { : . ?? [] },
		async ({  }) {
			try {
				const  = await .()
				(`Membership revision ${.} saved.`)
			} catch {
				(
					"The membership service did not respond. Your edits remain local.",
				)
			}
		},
	})
 
	if (. || .)
		return (
			< ="form-please-complex">
				Loading membership ladder…
			</>
		)
	if (. || .)
		return (
			< ="form-please-complex">
				Could not load the membership editor.
			</>
		)
	let  = 
	if (.)  = "Saving ladder…"
	const  = ..()
 
	return (
		<
			="Membership ladder example"
			="form-please-complex"
		>
			< ="form-please-complex__kicker">Cascading four-tier editor</>
			< ="form-please-complex__summary">
				Four nested benefit arrays, monotonic reductions, a remote workspace
				connection, and calendar-assisted pause windows stay synchronized.
			</>
			<. ="form-please-complex__form" ={}>
				<
					={..}
					={}
					={.}
				/>
				<
					="Membership ladder preview"
					="form-please-complex__preview"
				>
					<>Reduction ladder</>
					<>
						Seed {...}% → Sprout{" "}
						{...}% → Canopy{" "}
						{...}% → Founder{" "}
						{...}%
					</>
				</>
				< ={..} ={} />
				< ="form-please-complex__actions">
					<. ="form-please-complex__primary">
						Save membership ladder
					</.>
					< ="polite">{}</>
				</>
			</.>
		</>
	)
}
 
function <>(: , : number): <> {
	return new (() =>
		.(() => (), ),
	)
}

Compare the other workflows in Examples.