Getting Started
Quick Start
Get up and running with NovaForms in under 5 minutes. This guide will walk you through creating your first dynamic form.
Your First Form
Let's create a simple contact form to get started:
import { useState } from "react";
import { NovaForm, createFormHandler } from "nova-forms";
const fields = [
{ name: "firstName", title: "First Name", type: "string", width: 50 },
{ name: "lastName", title: "Last Name", type: "string", width: 50 },
{ name: "email", title: "Email", type: "email", width: 100 },
{ name: "phone", title: "Phone", type: "tel", width: 100 },
{ name: "message", title: "Message", type: "text", width: 100 },
{ name: "subscribe", title: "Subscribe to newsletter", type: "boolean", width: 100 },
];
export default function ContactForm() {
const [formData, setFormData] = useState({});
const handleChange = createFormHandler({
fields,
setState: setFormData,
});
const handleSubmit = (e) => {
e.preventDefault();
console.log("Form submitted:", formData);
};
return (
<form onSubmit={handleSubmit}>
<NovaForm
fields={fields}
onChange={handleChange}
formData={formData}
/>
<button type="submit" className="mt-4 px-4 py-2 bg-blue-500 text-white rounded">
Submit
</button>
</form>
);
}
That's it! You now have a fully functional form with:
- ✅ Responsive layout (50% width fields side by side)
- ✅ Email validation
- ✅ Phone number input
- ✅ Textarea for longer content
- ✅ Checkbox for subscription
Understanding the Code
Let's break down what's happening:
Field Definition
Each field is defined as an object with these key properties:
{
name: "firstName", // Unique identifier
title: "First Name", // Display label
type: "string", // Field type
width: 50 // Width percentage (25, 50, 75, 100)
}
Form Handler
The createFormHandler function manages form state and applies any rules or modifiers:
const handleChange = createFormHandler({
fields, // Your field definitions
setState: setFormData, // React setState function
});
Form Component
The NovaForm component renders your fields with automatic styling and validation:
<NovaForm
fields={fields} // Field definitions
onChange={handleChange} // Change handler
formData={formData} // Current form state
/>
Adding Conditional Logic
Let's enhance our form with conditional fields. We'll show a "Company" field only when the user selects "Business" as their inquiry type:
const fields = [
{ name: "firstName", title: "First Name", type: "string", width: 50 },
{ name: "lastName", title: "Last Name", type: "string", width: 50 },
{ name: "email", title: "Email", type: "email", width: 100 },
{
name: "inquiryType",
title: "Inquiry Type",
type: "select",
width: 100,
options: [
{ value: "personal", label: "Personal" },
{ value: "business", label: "Business" }
]
},
{
name: "company",
title: "Company",
type: "string",
width: 100,
conditions: {
hiddenWhen: {
field: "inquiryType",
when: "not equal to",
value: "business"
}
}
},
{ name: "message", title: "Message", type: "text", width: 100 },
];
Now the "Company" field will only appear when "Business" is selected!
Adding Validation
Let's add some validation rules to our form:
const fields = [
{
name: "firstName",
title: "First Name",
type: "string",
width: 50,
required: true,
pattern: /^[A-Za-z\s]+$/,
error: "First name must contain only letters and spaces"
},
{
name: "email",
title: "Email",
type: "email",
width: 100,
required: true,
error: "Please enter a valid email address"
},
{
name: "phone",
title: "Phone",
type: "tel",
width: 100,
pattern: /^\(\d{3}\) \d{3}-\d{4}$/,
placeholder: "(555) 123-4567",
error: "Please enter phone number in format (555) 123-4567"
},
];
Next Steps
Now that you have the basics down, explore these advanced features:
- Field Types - Learn about all 20+ built-in field types
- Rules System - Create complex conditional logic
- Custom Fields - Build your own field components
- Styling - Customize the appearance with Tailwind CSS
Common Patterns
Form with Subforms
const fields = [
{ name: "name", title: "Name", type: "string", width: 100 },
{
name: "addresses",
title: "Addresses",
type: "array",
width: 100,
fields: [
{ name: "street", title: "Street", type: "string", width: 100 },
{ name: "city", title: "City", type: "string", width: 50 },
{ name: "state", title: "State", type: "string", width: 50 },
]
}
];
Form with Calculations
const rules = [
{
name: "calculateTotal",
effects: [
{
targetField: "total",
prop: "value",
type: "multiply",
kind: "number",
value: 1.1 // Add 10% tax
}
]
}
];
const fields = [
{ name: "subtotal", title: "Subtotal", type: "number", width: 50 },
{
name: "total",
title: "Total (with tax)",
type: "number",
width: 50,
readOnly: true,
triggers: [
{
rule: "calculateTotal",
when: [{ field: "subtotal", when: "not empty" }]
}
]
}
];
Getting Help
If you run into any issues:
- Check the Installation guide for setup problems
- Browse the Examples for common patterns
- Join the GitHub Discussions for community help