Installation
Learn how to install and configure @saastro/forms in your React project.
Prerequisites
Before you begin, make sure you have:
- React 18 or later
- TypeScript 5.0 or later (recommended)
- A UI component library (we recommend shadcn/ui)
Quick Start (Recommended)
@saastro/forms ships with a CLI that scaffolds example forms and installs
everything they need — shadcn components and peer dependencies. The fastest
path is three commands:
# 1. Install the package
npm install @saastro/forms
# 2. Generate two example forms (zero-config) in src/components/
npx @saastro/forms init
# 3. Install any missing shadcn components AND peer dependencies
npx @saastro/forms install-deps
That’s it. Open src/components/ExampleForm.tsx to see a FormBuilder example,
or src/components/ExampleFormJson.tsx for the equivalent JSON-config form.
Vite only: the scaffolded examples auto-discover components with
import.meta.glob, which is a Vite feature — it does not exist in Next.js, webpack, or other bundlers. On non-Vite setups, pass components explicitly via thecomponentsprop instead (see Explicit Components below and the Recipes for framework-specific examples).
See the CLI reference for every flag and option.
How init and install-deps work
initcreates two example files insrc/components/:ExampleForm.tsx— programmatic form withFormBuilderExampleFormJson.tsx— JSON-config form with auto-discovered components
install-deps:- Reads your project’s
components.json(shadcn config) and runsshadcn@latest add ...for any required components that are missing. - Detects your package manager from the lockfile and installs any missing
peer dependencies (
zod,react-hook-form,react-day-picker,date-fns).
- Reads your project’s
Both commands need a components.json (shadcn config) in your project root and
exit if it’s missing — if you don’t have one yet, run npx shadcn@latest init
first.
Use the form in your page
import { ExampleForm } from '@/components/ExampleForm';
export default function ContactPage() {
return <ExampleForm />;
}
The form auto-discovers shadcn components via Vite’s import.meta.glob. No
FormProvider and no barrel file required.
Manual Setup
If you prefer to wire things up by hand, follow these four steps instead of running the CLI.
1. Install the package
npm install @saastro/forms
# or
pnpm add @saastro/forms
# or
bun add @saastro/forms
2. Import the stylesheet
Add this once to your app entry point (e.g. main.tsx, layout.tsx, or globals.css):
import '@saastro/forms/styles.css'
This provides the selected-state styles for button groups (button-radio, button-checkbox, button-card). It uses CSS custom properties from your design system — no Tailwind compilation needed.
Server Components / SSR:
@saastro/formsis a client-side library (hooks, state, events) but is safe to import on the server — allwindow/documentaccess is guarded. In React Server Components setups (Next.js App Router), render<Form>inside a'use client'boundary.
3. Install peer dependencies
@saastro/forms requires React Hook Form, Zod, date-fns, and react-day-picker:
npm install react-hook-form zod date-fns react-day-picker
3. Install shadcn/ui components
Install only the components you need. For a basic text form:
npx shadcn@latest add input button label field form
For all available field types:
npx shadcn@latest add input button label textarea select checkbox radio-group popover calendar tooltip slider switch separator dialog command input-otp native-select field form
4. Create your first form (Zero-Config)
If your project uses Vite, auto-discover all your shadcn components with
import.meta.glob:
import { Form, FormBuilder } from '@saastro/forms';
const uiComponents = import.meta.glob('@/components/ui/*.tsx', { eager: true });
const config = FormBuilder.create('contact')
.addField('name', (f) => f.type('text').label('Name').required().minLength(2))
.addField('email', (f) => f.type('email').label('Email').required().email())
.addStep('main', ['name', 'email'])
.buttons({ submit: { type: 'submit', label: 'Send' } })
.build();
export function ContactForm() {
return (
<Form
config={config}
components={uiComponents}
onSubmit={(values) => console.log('Submitted:', values)}
/>
);
}
No FormProvider, no barrel file, no manual component registration. The Form
auto-discovers components by parsing the glob result.
Not using Vite?
import.meta.globis Vite-specific. On Next.js, webpack, or any other bundler, skip this step and pass the components explicitly — the next section shows how, and it works everywhere.
Alternative: Explicit Components
If you’re not using Vite, prefer explicit imports, or need to override specific
components, pass them directly to the components prop. This works with every
bundler:
import { Form, FormBuilder } from '@saastro/forms';
import { Input } from '@/components/ui/input';
import { Button } from '@/components/ui/button';
import { Label } from '@/components/ui/label';
import { Field, FieldLabel, FieldDescription, FieldError } from '@/components/ui/field';
import { FormField, FormControl } from '@/components/ui/form';
<Form
config={config}
components={{
Input,
Button,
Label,
Field,
FieldLabel,
FieldDescription,
FieldError,
FormField,
FormControl,
}}
/>;
Provider Mode (Legacy)
For apps with many forms sharing the same components, you can use the provider pattern:
import { Form, FormBuilder, ComponentProvider, createComponentRegistry } from '@saastro/forms';
import * as shadcn from '@/lib/form-components'; // Your barrel file
const registry = createComponentRegistry(shadcn);
export function App() {
return (
<ComponentProvider components={registry}>
<ContactForm />
<SignupForm />
<CheckoutForm />
</ComponentProvider>
);
}
function ContactForm() {
const config = FormBuilder.create('contact')
.addField('name', (f) => f.type('text').label('Name').required())
.addStep('main', ['name'])
.build();
return <Form config={config} />;
}
Benefits of Zero-Config
Zero-config mode requires Vite, but when available it’s the least amount of code:
- One line of setup — just
import.meta.globand you’re done - Auto-discovers components — no manual registration needed
- Missing component fallback — shows helpful warnings with the install command
- No Provider boilerplate — just render
<Form /> - Override per-form — to replace a discovered component, convert the glob
with
parseGlobModules(exported from@saastro/forms) and spread your override over the result:components={{ ...parseGlobModules(modules), Input: MyInput }}
Required Components by Field Type
When a component is missing, you’ll see a helpful warning with the recommended
fix: npx @saastro/forms install-deps.
| Field Type | Required Components |
|---|---|
text, email, tel | Input, Label, Field, FieldLabel, FieldDescription, FieldError, FormField, FormControl |
textarea | Textarea, Label, Field, FieldLabel, FieldDescription, FieldError, FormField, FormControl |
select | Select, SelectTrigger, SelectContent, SelectItem, SelectValue, Field, … |
checkbox, switch | Checkbox/Switch, Label, Field, … |
date | Calendar, Popover, PopoverTrigger, PopoverContent, Button, Field, … |
combobox | Command, CommandInput, CommandList, Popover, Button, Field, … |
Check Required Components Programmatically
import { getRequiredComponents, getInstallCommand } from '@saastro/forms';
const required = getRequiredComponents(config);
// ['Input', 'Button', 'Label', 'Field', ...]
const installCmd = getInstallCommand(required);
// 'npx shadcn@latest add input button label field form'
Tailwind CSS 4
If you’re using Tailwind CSS 4, add the following @source directive to your main CSS file so Tailwind can detect the classes used by this package:
@source "node_modules/@saastro/forms/dist/**/*.js";
TypeScript Configuration
@saastro/forms itself has no special TypeScript requirements. The settings
below are what the examples in these docs (and the CLI-generated files) assume:
{
"compilerOptions": {
"strict": true,
"moduleResolution": "bundler",
"paths": {
"@/*": ["./src/*"]
}
}
}
The @/* paths alias is the standard shadcn/ui convention — it’s where the
examples import UI components from (@/components/ui/...). Adjust it to match
your project layout if yours differs.
Next Steps
- Read the CLI reference for every CLI command and flag
- Learn the FormBuilder API — the recommended way to build forms
- Set up Validation — Zod schemas or declarative rules
- Build Multi-Step Forms — wizards with conditional routing
- Browse the Field Types to see all available fields
- Check the Recipes for framework-specific setups (Next.js and other non-Vite bundlers)