Appearance
Getting Started with FormDSL (React)
Build complex, multi-section forms with a declarative JSX DSL. No backend required.
Install
bash
npm install @formdsl/reactImport the stylesheet
In your app entry point (e.g., main.tsx or layout.tsx):
tsx
import '@formdsl/react/styles'Your first form
tsx
import { Form, Section, Question, Row } from '@formdsl/react'
export default function ContactForm() {
return (
<Form id="contact" version="1.0" onSubmit={(answers) => {
console.log(answers)
// { name: "Jane", email: "jane@example.com", phone: "555-1234" }
}}>
<Section title="Contact Info">
<Question id="name" type="text" required label="Full Name" />
<Row>
<Question id="email" type="email" required label="Email" />
<Question id="phone" type="tel" label="Phone" format="phone" />
</Row>
</Section>
</Form>
)
}That's it. You get validation, error messages, and a submit button out of the box.
Add more sections
Add multiple <Section> components and pick a navigation mode:
tsx
<Form id="application" version="1.0" navigation="stepper"
onSubmit={(answers) => saveToDatabase(answers)}>
<Section title="Personal">
<Question id="name" type="text" required label="Full Name" />
<Question id="dob" type="date" required label="Date of Birth" />
</Section>
<Section title="Employment">
<Question id="employer" type="text" label="Current Employer" />
<Question id="salary" type="currency" label="Annual Salary" />
</Section>
<Section title="Preferences">
<Question id="contact" type="radio" required label="Preferred Contact" options={[
{ value: 'email', label: 'Email' },
{ value: 'phone', label: 'Phone' },
{ value: 'mail', label: 'Mail' },
]} />
</Section>
<Review />
</Form>Navigation modes: "sidebar", "stepper", "tabs", or "none" (single scrollable page).
Conditional fields
Use showIf to show/hide fields based on other answers. Uses MongoDB-style operators:
tsx
<Question id="employed" type="yesno" label="Are you employed?" />
{/* Only shown when employed = true */}
<Question id="employer" type="text" label="Employer"
showIf={{ employed: true }} />
{/* Required only when employed */}
<Question id="jobTitle" type="text" label="Job Title"
requiredIf={{ employed: true }} />
{/* Comparison operators */}
<Question id="seniorDiscount" type="checkbox" label="Senior discount"
showIf={{ age: { gte: 65 } }} />
{/* OR conditions */}
<Banner variant="info" showIf={{ $or: [{ country: "US" }, { country: "CA" }] }}>
North American residents qualify for free shipping.
</Banner>Repeatable groups
Let users add/remove sets of fields:
tsx
<Repeat id="dependents" label="Dependents" collapsible
itemLabel="{{firstName}} {{lastName}}" minItems={0} maxItems={10}>
<Row>
<Question id="firstName" type="text" required label="First Name" />
<Question id="lastName" type="text" required label="Last Name" />
</Row>
<Question id="relationship" type="select" required label="Relationship" options={[
{ value: 'child', label: 'Child' },
{ value: 'spouse', label: 'Spouse' },
{ value: 'parent', label: 'Parent' },
]} />
</Repeat>Calculated fields
Formulas auto-compute based on other answers:
tsx
<Question id="qty" type="number" required label="Quantity" min={1} />
<Question id="price" type="currency" required label="Unit Price" />
<Question id="subtotal" type="currency" label="Subtotal"
formula="{{qty}} * {{price}}" />
<Question id="tax" type="currency" label="Tax"
formula="{{subtotal}} * 0.08" />
<Question id="total" type="currency" label="Total"
formula="{{subtotal}} + {{tax}}" />Built-in functions: SUM, COUNT, MIN, MAX, IF, ROUND.
Layout components
tsx
import { Form, Section, Question, Row, Card, Banner, Divider } from '@formdsl/react'
<Section title="Details">
<Banner variant="info" title="Note">
All fields marked with * are required.
</Banner>
<Card title="Address">
<Question id="street" type="text" required label="Street" />
<Row>
<Question id="city" type="text" required label="City" />
<Question id="state" type="text" required label="State" />
<Question id="zip" type="text" required label="ZIP" format="zip" />
</Row>
</Card>
<Divider />
<Question id="notes" type="textarea" label="Additional Notes" rows={4} />
</Section>Theming
Override CSS variables to match your brand:
css
.my-form {
--fb-primary: #e11d48;
--fb-radius: 8px;
--fb-font-family: 'Inter', sans-serif;
}tsx
<Form id="styled" class="my-form" ...>Built-in themes: "default" and "printed". See the theming reference for all CSS variables.
Field types
FormDSL includes 30+ field types:
| Type | Description |
|---|---|
text, email, tel, url | Text inputs with optional masks |
textarea | Multi-line text |
number, currency | Numeric with formatting, formulas |
date, datetime, time, year, month | Date/time pickers |
select, radio, multicheck | Choice fields |
boolean, checkbox, yesno | True/false inputs |
rating | Stars or number scale |
file | File upload (MIME validation, max size) |
signature | Signature pad |
tags | Tag input with autocomplete |
matrix | Radio grid (Likert scales) |
ranking | Drag-and-drop reorder |
country | Searchable country picker |
hidden | Hidden tracking field |
custom | Bring your own component |
Input masks: "ssn", "ein", "phone", "zip", "zip+4", or any custom IMask pattern.
SolidJS support
FormDSL also ships @formdsl/solid with an identical API:
tsx
import { Form, Section, Question } from '@formdsl/solid'
import '@formdsl/solid/styles'What's next
- Connected Mode — Add a backend for auto-save, submissions dashboard, file uploads, and webhooks
- DSL Reference — Complete API reference for all components and props
- Theming — CSS variables, layers, and custom themes
- Self-Hosting — Deploy your own FormDSL server
Get in touch
FormDSL is in early access. Questions, feedback, or want to try it out? Reach out at hello@formdsl.dev.