Rilaykit Logorilaykit ✨
Getting started

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.

lib/components.tsx
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:

lib/rilay.ts
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.

lib/contactForm.ts
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 changes
  • conditions: Control when fields are visible or enabled
  • props: 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.

components/ContactForm.tsx
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:

pages/contact.tsx
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:

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.