Skip to content
ARC UI ARC Reactive Components
Docs Components Tokens Synthesizer
v2.1.0
Getting Started Frameworks Design Tokens Theming Theme Synthesizer Accessibility Browser Support Changelog Contributing All Components App ShellAspect GridAuth ShellCenterClusterContainerDashboard GridDockFloat BarInsetMasonryPage HeaderPage LayoutResizableResponsive SwitcherSectionSettings LayoutSplit PaneStatus BarStickyToolbar Anchor NavBottom NavBreadcrumbBreadcrumb MenuCommand BarDrawerFooterLinkNavigation MenuPage IndicatorPaginationRailScroll IndicatorScroll SpyScroll To TopSidebarSkip LinkSpeed DialStepper NavTabsTop BarTree View AccordionAspect RatioAvatarAvatar GroupCalloutCardCarouselCollapsibleColor SwatchCTA BannerDividerEmpty StateFeature CardIconImageInfinite ScrollMarqueeScroll AreaSeparatorSkeletonSpinnerStackVirtual List Animated NumberBadgeComparisonCountdown TimerData TableDescription ListDiffKey ValueListMeterSparklineStatStepperTableTagTimelineValue Card BlockquoteCode BlockGradient TextHighlightKbdMarkdownNumber FormatProseTextTime AgoTruncateTypewriter ButtonButton GroupCalendarCheckboxChipColor PickerComboboxCopy ButtonDate PickerFieldsetFile UploadFormHotkeyIcon ButtonInputInput GroupLabelMulti SelectNumber InputOTP InputPin InputRadio GroupRange SliderRatingSearchSegmented ControlSelectSliderSortable ListSwitch GroupTextareaTheme ToggleTime PickerToggle AlertAnnouncementBannerCommand PaletteConfirmConnection StatusContext MenuDialogDropdown MenuGuided TourHover CardInline MessageLoading OverlayModalNotification PanelPopoverProgressProgress ToastSheetSnackbarSpotlightToastTooltip
Components Form
input interactive
<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

Send message

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