Form (preview)

Build forms with the Radix UI Form component, supports built-in validation and custom validation.


Contact Us

Attention

At the moment, the Form component is still in preview mode. It is not recommended to use it in production. Use with caution. We will continue to improve the component and add more features in the future.

Browse the Storybook for more examples.

Automatic Installation

This method is still working on progress, please use manual installation for now.

Manual Installation

Install dependencies

npm install radix-ui

Copy the code

components/form/form.tsx
import { Form as FormPrimitive } from 'radix-ui'
import * as React from 'react'
import { ButtonStyles, buttonStyles } from '#/components/button'
import { type FormStyles, formStyles } from './form.css'
 
const Form = React.forwardRef<
  React.ComponentRef<typeof FormPrimitive.Root>,
  React.ComponentPropsWithoutRef<typeof FormPrimitive.Root> & FormStyles
>(({ className, size, hasError, ...props }, forwardedRef) => {
  const styles = formStyles({ size, hasError })
  return <FormPrimitive.Root ref={forwardedRef} className={styles.root({ className })} {...props} />
})
 
const FormField = React.forwardRef<
  React.ComponentRef<typeof FormPrimitive.Field>,
  React.ComponentPropsWithoutRef<typeof FormPrimitive.Field> & FormStyles
>(({ className, size, hasError, ...props }, forwardedRef) => {
  const styles = formStyles({ size, hasError })
  return (
    <FormPrimitive.Field ref={forwardedRef} className={styles.field({ className })} {...props} />
  )
})
 
const FormLabel = React.forwardRef<
  React.ComponentRef<typeof FormPrimitive.Label>,
  React.ComponentPropsWithoutRef<typeof FormPrimitive.Label> & FormStyles
>(({ className, size, hasError, ...props }, forwardedRef) => {
  const styles = formStyles({ size, hasError })
  return (
    <FormPrimitive.Label ref={forwardedRef} className={styles.label({ className })} {...props} />
  )
})
 
/**
 * TODO: At the moment, it is not possible to compose Form with Radix's other form primitives such as Checkbox, Select, etc.
 * @see: https://www.radix-ui.com/primitives/docs/components/form#composing-with-your-own-components
 */
const FormControl = React.forwardRef<
  React.ComponentRef<typeof FormPrimitive.Control>,
  React.ComponentPropsWithoutRef<typeof FormPrimitive.Control> & FormStyles
>(({ className, size, hasError, asChild, ...props }, forwardedRef) => {
  const styles = formStyles({ size, hasError })
  return (
    <FormPrimitive.Control
      ref={forwardedRef}
      className={styles.control({ className })}
      asChild={asChild}
      {...props}
    />
  )
})
 
const FormMessage = React.forwardRef<
  React.ComponentRef<typeof FormPrimitive.Message>,
  React.ComponentPropsWithoutRef<typeof FormPrimitive.Message> & FormStyles
>(({ className, size, hasError, ...props }, forwardedRef) => {
  const styles = formStyles({ size, hasError })
  return (
    <FormPrimitive.Message
      ref={forwardedRef}
      className={styles.message({ className })}
      {...props}
    />
  )
})
 
const FormValidityState = (
  props: React.ComponentPropsWithoutRef<typeof FormPrimitive.ValidityState>
) => {
  return <FormPrimitive.ValidityState {...props} />
}
 
const FormSubmit = React.forwardRef<
  React.ComponentRef<typeof FormPrimitive.Submit>,
  React.ComponentPropsWithoutRef<typeof FormPrimitive.Submit> &
    Pick<ButtonStyles, 'variant' | 'size' | 'isLoading'>
>(({ className, size, variant = 'primary', isLoading, ...props }, forwardedRef) => {
  const styles = buttonStyles({ variant, size, isLoading })
  return (
    <FormPrimitive.Submit ref={forwardedRef} className={styles.base({ className })} {...props}>
      {props.children && <span className={styles.span()}>{props.children}</span>}
    </FormPrimitive.Submit>
  )
})
 
Form.displayName = FormPrimitive.Root.displayName
FormField.displayName = FormPrimitive.Field.displayName
FormLabel.displayName = FormPrimitive.Label.displayName
FormControl.displayName = FormPrimitive.Control.displayName
FormMessage.displayName = FormPrimitive.Message.displayName
FormValidityState.displayName = FormPrimitive.ValidityState.displayName
FormSubmit.displayName = FormPrimitive.Submit.displayName
 
export { Form, FormField, FormLabel, FormControl, FormMessage, FormValidityState, FormSubmit }

Usage

Imports

import {
  Form,
  FormField,
  FormLabel,
  FormControl,
  FormMessage,
  FormValidityState,
  FormSubmit
} from '#/components/form'

Example

Browse the Storybook for more examples.

Anatomy

<Form>
  <FormField>
    <FormLabel />
    <FormControl />
    <FormMessage />
    <FormValidityState />
  </FormField>
 
  <FormMessage />
  <FormValidityState />
 
  <FormSubmit />
</Form>
Edit on GitHub

Last updated on

On this page