<arc-form> Overview
Guidelines
When to use
- Wrap all related fields inside a single Form so validation and submission are coordinated
- Give every field a unique `name` so FormData serialisation produces the correct key-value pairs
- Set `required` on mandatory fields and let Form handle the validation messaging
- Provide a clear submit Button with `type="submit"` as the last child of the Form
- Use the `loading` prop to indicate an async submission in progress and prevent duplicate requests
- Listen for `arc-submit` instead of native `submit` to receive validated, serialised data
- Include meaningful labels on every field so the error summary is readable
When not to use
- Do not nest one Form inside another -- HTML forbids nested forms and behaviour is undefined
- Do not handle validation manually when the built-in constraint API already covers your rules
- Do not rely solely on client-side validation -- always validate on the server as well
- Do not place the submit Button outside the Form; it will not trigger submission
- Avoid calling `event.preventDefault()` on `arc-submit` unless you need to cancel the submission
- Do not use `novalidate` as a permanent workaround for broken validation -- fix the constraints instead
Features
- Intercepts native form submission and runs constraint validation on all associated fields
- Aggregates per-field errors and displays an optional error summary above the submit button
- Emits `arc-submit` with a serialised FormData payload only when validation passes
- Supports `novalidate` to bypass built-in checks for custom validation flows
- Coordinates `disabled` state -- disabling the form disables every child field
- Works with any form-associated element, including native inputs and ARC UI components
- Prevents double-submission by disabling the submit button while `loading` is true
- Reset support via `arc-reset` event and programmatic `.reset()` method
- Keyboard-accessible -- Enter key inside a single-line input triggers submission
- Pairs with Input, Textarea, Select, Checkbox, and RadioGroup without extra wiring
Preview
Usage
This component requires JavaScript. No pure HTML/CSS version is available — use the Web Component directly or a framework wrapper.
<arc-form>
<div style="display:flex; flex-direction:column; gap:16px; width:100%; max-width:480px;">
<arc-input label="Name" name="name" placeholder="Jane Doe" required></arc-input>
<arc-input label="Email" name="email" type="email" placeholder="jane@example.com" required></arc-input>
<arc-textarea label="Message" name="message" rows="4" placeholder="How can we help?" required></arc-textarea>
<arc-button variant="primary" type="submit">Send message</arc-button>
</div>
</arc-form>
<script>
document.querySelector('arc-form')
.addEventListener('arc-submit', (e) => {
console.log('Form data:', Object.fromEntries(e.detail.formData));
});
</script> import { Button, Form, Input, Textarea } from '@arclux/arc-ui-react';
function ContactForm() {
const handleSubmit = (e: CustomEvent) => {
const data = Object.fromEntries(e.detail.formData);
console.log('Form data:', data);
};
return (
<Form onArcSubmit={handleSubmit}>
<div style={{ display: 'flex', flexDirection: 'column', gap: 16, width: '100%', maxWidth: 480 }}>
<Input label="Name" name="name" placeholder="Jane Doe" required />
<Input label="Email" name="email" type="email" placeholder="jane@example.com" required />
<Textarea label="Message" name="message" rows={4} placeholder="How can we help?" required />
<Button variant="primary" type="submit">Send message</Button>
</div>
</Form>
);
} <script setup>
import { Button, Form, Input, Textarea } from '@arclux/arc-ui-vue';
function handleSubmit(e) {
const data = Object.fromEntries(e.detail.formData);
console.log('Form data:', data);
}
</script>
<template>
<Form @arc-submit="handleSubmit">
<div style="display:flex; flex-direction:column; gap:16px; width:100%; max-width:480px;">
<Input label="Name" name="name" placeholder="Jane Doe" required />
<Input label="Email" name="email" type="email" placeholder="jane@example.com" required />
<Textarea label="Message" name="message" rows="4" placeholder="How can we help?" required />
<Button variant="primary" type="submit">Send message</Button>
</div>
</Form>
</template> <script>
import { Button, Form, Input, Textarea } from '@arclux/arc-ui-svelte';
function handleSubmit(e) {
const data = Object.fromEntries(e.detail.formData);
console.log('Form data:', data);
}
</script>
<Form on:arc-submit={handleSubmit}>
<div style="display:flex; flex-direction:column; gap:16px; width:100%; max-width:480px;">
<Input label="Name" name="name" placeholder="Jane Doe" required />
<Input label="Email" name="email" type="email" placeholder="jane@example.com" required />
<Textarea label="Message" name="message" rows="4" placeholder="How can we help?" required />
<Button variant="primary" type="submit">Send message</Button>
</div>
</Form> import { Component } from '@angular/core';
import { Button, Form, Input, Textarea } from '@arclux/arc-ui-angular';
@Component({
imports: [Button, Form, Input, Textarea],
template: `
<Form (arc-submit)="handleSubmit($event)">
<div style="display:flex; flex-direction:column; gap:16px; width:100%; max-width:480px;">
<Input label="Name" name="name" placeholder="Jane Doe" required></Input>
<Input label="Email" name="email" type="email" placeholder="jane@example.com" required></Input>
<Textarea label="Message" name="message" rows="4" placeholder="How can we help?" required></Textarea>
<Button variant="primary" type="submit">Send message</Button>
</div>
</Form>
`,
})
export class ContactFormComponent {
handleSubmit(e: CustomEvent) {
const data = Object.fromEntries(e.detail.formData);
console.log('Form data:', data);
}
} import { Button, Form, Input, Textarea } from '@arclux/arc-ui-solid';
function ContactForm() {
const handleSubmit = (e: CustomEvent) => {
const data = Object.fromEntries(e.detail.formData);
console.log('Form data:', data);
};
return (
<Form onArcSubmit={handleSubmit}>
<div style={{ display: 'flex', 'flex-direction': 'column', gap: '16px', width: '100%', 'max-width': '480px' }}>
<Input label="Name" name="name" placeholder="Jane Doe" required />
<Input label="Email" name="email" type="email" placeholder="jane@example.com" required />
<Textarea label="Message" name="message" rows={4} placeholder="How can we help?" required />
<Button variant="primary" type="submit">Send message</Button>
</div>
</Form>
);
} import { Button, Form, Input, Textarea } from '@arclux/arc-ui-preact';
function ContactForm() {
const handleSubmit = (e: CustomEvent) => {
const data = Object.fromEntries(e.detail.formData);
console.log('Form data:', data);
};
return (
<Form onArcSubmit={handleSubmit}>
<div style={{ display: 'flex', flexDirection: 'column', gap: 16, width: '100%', maxWidth: 480 }}>
<Input label="Name" name="name" placeholder="Jane Doe" required />
<Input label="Email" name="email" type="email" placeholder="jane@example.com" required />
<Textarea label="Message" name="message" rows={4} placeholder="How can we help?" required />
<Button variant="primary" type="submit">Send message</Button>
</div>
</Form>
);
} API
| Prop | Type | Default | Description |
|---|---|---|---|
action | string | '' | Form action URL for native form submission. When set, the form submits to this URL using the browser's built-in mechanism. |
method | string | '' | HTTP method for native form submission (GET or POST). Only applies when action is set. |
novalidate | boolean | false | When true, skips built-in constraint validation on submit. Use this when you need to implement a fully custom validation flow while still leveraging Form for data serialisation. |
loading | boolean | false | Indicates an asynchronous submission is in progress. Disables the submit button and shows a loading indicator to prevent duplicate requests. |
disabled | boolean | false | Disables the entire form, propagating the disabled state to every child field. Useful for read-only previews or while awaiting permissions. |
errorSummary | boolean | true | When true, renders an aggregated list of validation errors above the submit area after a failed submission attempt. Set to false to handle error display manually. |
Events
| Event | Description |
|---|---|
arc-submit | Fired on valid form submission with serialized form data |
arc-invalid | Fired when validation fails, with error details |
arc-reset | Fired when the form is reset via the .reset() method |
See Also
- Input Versatile form control supporting single-line text, email, password, and multiline textarea modes with built-in label, placeholder, and validation states. Pairs with Form for complete data-entry workflows.
- Select Dropdown select with searchable options, keyboard navigation, and full ARIA listbox semantics for accessible form inputs.
- Checkbox Multi-select form control supporting checked, indeterminate, and disabled states. Ideal for preferences, bulk-selection patterns, and consent forms where users need to toggle one or more independent options.
- Toggle On/off switch with smooth animation, glow effect, and ARIA switch role.
- Textarea Multi-line text input with integrated label, placeholder, resize control, and live character count that turns red at the limit.
- Button Primary call-to-action element with three visual variants that map to action hierarchy. Supports prefix and suffix slots for icons. Renders as an anchor when given an href, making it ideal for navigation-driven actions across landing pages, toolbars, and forms.