Building Forms
How to use the fluent API to build form configurations.
Building a form configuration starts from your central rilay
instance. By calling rilay.form()
, you get a form builder that has access to all your pre-configured components and renderers.
Before proceeding, make sure you have created and configured a shared rilay
instance as shown in the Your First Form guide.
The Form Building Process
1. Start with form()
Call .form()
on your rilay
instance to begin a new form definition. You should provide a unique ID for your form.
import { rilay } from '@/lib/rilay';
const loginForm = rilay.form('login');
2. Add Fields and Rows
The builder provides a powerful polymorphic .add()
method that handles multiple use cases:
- Single field:
.add(fieldConfig)
- Adds a field on its own row - Multiple fields:
.add(field1, field2, field3)
- Adds multiple fields on the same row (max 3) - Array syntax:
.add([field1, field2], options)
- Explicit row control with options
const registrationForm = rilay
.form('registration')
// Add multiple fields on the same row
.add(
{
id: 'firstName',
type: 'text', // This type must exist in your component registry
props: { label: 'First Name' },
},
{
id: 'lastName',
type: 'text',
props: { label: 'Last Name' },
}
)
// Add a single field on its own row
.add({
id: 'email',
type: 'email', // Assumes an 'email' type is registered
props: { label: 'Email Address' },
});
You can also use the array syntax for explicit control over row options:
const formWithOptions = rilay
.form('styled-form')
.add([
{ id: 'field1', type: 'text', props: { label: 'Field 1' } },
{ id: 'field2', type: 'text', props: { label: 'Field 2' } },
], {
spacing: 'loose',
alignment: 'center'
});
Auto-Generated IDs
One of the key improvements in the new API is automatic ID generation. If you don't provide an id
field, one will be generated for you:
const quickForm = rilay
.form('quick-form')
.add(
{ type: 'text', props: { label: 'Name' } }, // Will get id: 'field-1'
{ type: 'email', props: { label: 'Email' } }, // Will get id: 'field-2'
{ type: 'text', props: { label: 'Phone' } } // Will get id: 'field-3'
);
When to use .build()
You may have noticed we don't always call .build()
in our examples. This is because components like <Form>
and workflow steps are smart enough to build the configuration for you.
However, you should call .build()
manually when you need the final, serializable FormConfiguration
object. For instance:
- To serialize the form and save it as JSON.
- To pass the configuration to a custom function or a third-party tool.
- For debugging purposes, to inspect the generated configuration.
const formConfig = rilay
.form('my-form')
.add({ id: 'field1', type: 'text' })
.build(); // Manually build the config
console.log(formConfig.allFields);
Field Configuration
The fieldConfig
object you pass to .add()
has the following shape:
interface FieldConfig {
id?: string; // Optional - auto-generated if not provided
type: string; // The component type to render from your registry
props?: Record<string, any>; // Props passed to your component renderer
}
Complete Example: Login Form
Let's tie everything together. Here is how you would build a complete login form configuration, assuming you have a configured rilay
instance. This definition can be passed directly to the <Form>
component.
import { rilay } from '@/lib/rilay';
export const loginForm = rilay
.form('login-form')
.add(
{
id: 'email',
type: 'email',
props: {
label: 'Email Address',
placeholder: 'Enter your email',
},
},
{
id: 'password',
type: 'password',
props: {
label: 'Password',
placeholder: 'Enter your password',
},
}
);
This loginForm
builder instance is now ready to be passed to your <Form>
component.