Skip to main content
Version: Current

Primus Form

PrimusForm is a compound wrapper component that manages form state, validation, loading, and error display in one place. Use it when you need multi-field forms with server-side validation feedback.

For simpler forms, use individual Input, Select, and Button components directly with @primus/ui-core HTML.

Components used

Input · Select · Textarea · Button · Toggle · FormField

Preview · Primus Form

Code

<form class="vstack" style="gap:1.125rem">

<!-- Form-level error -->
<div role="alert" data-variant="danger">
Please fix the errors below before continuing.
</div>

<!-- Field with validation error -->
<div data-field="error">
<label>Admin email <span style="color:var(--danger)">*</span></label>
<input type="email" aria-invalid="true" />
<span class="error">Please enter a valid email address.</span>
</div>

<!-- Valid field -->
<label data-field>
Tenant name <span style="color:var(--danger)">*</span>
<input type="text" />
</label>

<!-- Select -->
<label data-field>
Plan
<select>
<option>Starter</option>
<option selected>Pro</option>
<option>Enterprise</option>
</select>
</label>

<!-- Toggle -->
<label>
<input type="checkbox" role="switch" checked />
Enable email notifications
</label>

<!-- Actions -->
<div style="display:flex;justify-content:flex-end;gap:0.75rem">
<button data-variant="secondary" type="reset">Cancel</button>
<button type="submit">Create tenant</button>
</div>

</form>

Props — PrimusForm (React)

PropTypeDefaultDescription
initialValuesRecord<string, any>{}Initial form field values
validate(values) => Record<string, string>Sync validation function, returns field error map
onSubmit(values, helpers) => Promise<void>requiredSubmit handler. helpers provides setError, setFieldErrors
children(bag) => ReactNoderequiredRender prop receiving form state

Form bag (render prop)

interface FormBag {
values: Record<string, any>;
errors: Record<string, string>; // field-level errors
touched: Record<string, boolean>;
formError: string; // form-level error
isLoading: boolean;
setFieldValue: (field: string, value: any) => void;
setError: (message: string) => void;
resetForm: () => void;
}

Angular: use Reactive Forms

Angular uses the built-in ReactiveFormsModule directly. Primus form components (Input, Select, Toggle) all support formControlName — no extra wrapper needed.

// Validators
import { Validators } from '@angular/forms';
this.form = this.fb.group({
email: ['', [Validators.required, Validators.email]],
seats: [10, [Validators.min(1), Validators.max(500)]],
});

// Show field error
fieldError(field: string): string {
const c = this.form.get(field);
if (!c?.touched || !c?.errors) return '';
if (c.errors['required']) return 'This field is required';
if (c.errors['email']) return 'Enter a valid email';
if (c.errors['min']) return 'Minimum value is 1';
return 'Invalid value';
}
Version history

See the Changelog for version history and breaking changes.