Your First Form
Build a complete contact form in under 10 minutes with validation, conditional logic, and type safety.
This guide walks you through building a complete contact form with RilayKit. You'll learn core concepts while creating something practical.
What You'll Build
A contact form with:
- 📝 Name, email, and message fields
- ✅ Real-time validation
- 🔗 Conditional field visibility
- 🎨 Custom component styling
- 🛡️ Full TypeScript type safety
Estimated time: 10 minutes • Prerequisites: Basic React and TypeScript knowledge
1. Create Component Renderers
RilayKit is headless — it handles logic while you provide the UI components. Let's create renderers for input fields.
A renderer is a React component that receives props from RilayKit (value, onChange, error, etc.) and renders your UI.
import { ComponentRenderer, ComponentRenderProps } from '@rilaykit/core';
// Define the props interface for our input component
interface InputProps {
label: string;
type?: 'text' | 'email' | 'password' | 'number';
placeholder?: string;
required?: boolean;
multiline?: boolean;
rows?: number;
}
// Create a flexible input renderer that handles different input types
export const InputRenderer: ComponentRenderer<InputProps> = ({
id,
value,
onChange,
onBlur,
error,
props
}) => {
const inputProps = {
id,
value: value || '',
onChange: (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) =>
onChange?.(e.target.value),
onBlur,
placeholder: props.placeholder,
className: `
block w-full rounded-md border px-3 py-2 text-sm
${error ? 'border-red-300 focus:border-red-500 focus:ring-red-500' :
'border-gray-300 focus:border-blue-500 focus:ring-blue-500'}
`
};
return (
<div className="space-y-1">
<label
htmlFor={id}
className="block text-sm font-medium text-gray-700"
>
{props.label}
{props.required && <span className="text-red-500 ml-1">*</span>}
</label>
{props.multiline ? (
<textarea {...inputProps} rows={props.rows || 3} />
) : (
<input {...inputProps} type={props.type || 'text'} />
)}
{error && (
<p className="text-sm text-red-600">{error[0].message}</p>
)}
</div>
);
};
Now let's configure RilayKit with our renderer:
import { ril } from '@rilaykit/core';
import { InputRenderer } from './components';
// Create and configure the RilayKit instance
export const rilay = ril
.create()
.addComponent('input', {
name: 'Input Field',
renderer: InputRenderer,
defaultProps: {
label: 'Input Field',
placeholder: 'Enter value...',
type: 'text'
}
});
2. Build the Form Configuration
Now we'll use RilayKit's fluent API to build our form. This declarative approach makes forms easy to read and modify.
import { required, email, minLength, when } from '@rilaykit/core';
import { rilay } from './rilay';
export const contactForm = rilay
.form('contact-us') // Unique form ID
.add({
id: 'name',
type: 'input',
props: {
label: 'Full Name',
placeholder: 'Enter your full name',
required: true,
type: 'text'
},
validation: [
required('Name is required'),
minLength(2, 'Name must be at least 2 characters')
]
})
.add({
id: 'email',
type: 'input',
props: {
label: 'Email Address',
placeholder: 'Enter your email address',
required: true,
type: 'email'
},
validation: [
required('Email is required'),
email('Please enter a valid email address')
]
})
.add({
id: 'message',
type: 'input',
props: {
label: 'Your Message',
placeholder: 'Tell us what\'s on your mind...',
required: true,
multiline: true,
rows: 4
},
validation: [
required('Message is required'),
minLength(10, 'Message must be at least 10 characters')
],
conditions: {
visible: when('email').exists() // Only show after email is entered
}
});
Key concepts:
validation
: Array of validator functions that run on field changesconditions
: Control when fields are visible or enabledprops
: Custom properties passed to your renderer component
3. Render the Form
Finally, let's create a React component that renders our form using RilayKit's <Form>
and <FormField>
components.
import React from 'react';
import { Form, FormField } from '@rilaykit/forms';
import { contactForm } from '@/lib/contactForm';
export function ContactForm() {
const handleSubmit = (data: { name: string; email: string; message: string }) => {
// Handle form submission - send to API, show success message, etc.
alert(`Thank you, ${data.name}! Your message has been received.`);
console.log('Form data:', data);
};
return (
<div className="max-w-md mx-auto bg-white shadow-lg rounded-lg p-6">
<h2 className="text-2xl font-bold text-gray-900 mb-6">Contact Us</h2>
<Form
formConfig={contactForm}
onSubmit={handleSubmit}
defaultValues={{ name: '', email: '', message: '' }}
className="space-y-4"
>
<FormField fieldId="name" />
<FormField fieldId="email" />
<FormField fieldId="message" />
<button
type="submit"
className="w-full bg-blue-600 hover:bg-blue-700 text-white font-medium py-2 px-4 rounded-md transition-colors"
>
Send Message
</button>
</Form>
</div>
);
}
Use it anywhere in your app:
import { ContactForm } from '@/components/ContactForm';
export default function ContactPage() {
return (
<div className="min-h-screen bg-gray-50 py-12">
<div className="container mx-auto px-4">
<ContactForm />
</div>
</div>
);
}
🎉 Congratulations!
You've built a complete contact form with RilayKit! Here's what you accomplished:
- ✅ Created reusable component renderers that work with any UI library
- ✅ Built a type-safe form with intelligent autocompletion
- ✅ Added real-time validation with custom error messages
- ✅ Implemented conditional logic (message field appears after email)
- ✅ Handled form submission with properly typed data
Next Steps
Now that you understand the basics, explore more advanced features:
- Examples Gallery - See RilayKit with different UI libraries
- Advanced Forms - Learn about dynamic fields, async validation, and complex conditions
- Multi-Step Workflows - Create onboarding flows and wizards
- Validation Adapters - Integrate Zod, Yup, or Joi
Common Questions
How do I style the form differently?
Update your component renderers with different CSS classes or use CSS-in-JS libraries. RilayKit is completely UI-agnostic.
Can I use this with Material-UI/Chakra/Ant Design?
Absolutely! Check our Examples Gallery for integration examples with popular UI libraries.
How do I add more validation rules?
RilayKit includes many built-in validators, or you can create custom ones. See Validation Guide for details.
Is this production-ready?
Yes! RilayKit is built for production use with full TypeScript support, comprehensive testing, and performance optimizations.