Skip to content

Form

Component form cung cấp validation, xử lý lỗi và các form controls dễ tiếp cận.

Cài đặt

bash
npx @galaxy-stack/nebula-cli@latest add form
bash
pnpm dlx @galaxy-stack/nebula-cli@latest add form
bash
yarn dlx @galaxy-stack/nebula-cli@latest add form
bash
bunx @galaxy-stack/nebula-cli@latest add form
bash
# Nếu bạn đã cài đặt galaxy-design toàn cục
galaxy-design add form

Dependencies

Component này tự động cài đặt các dependencies sau:

  • React: react-hook-form, @radix-ui/react-label
  • Vue: radix-vue, vee-validate
  • Angular: @angular/forms, @radix-ng/primitives
  • React Native: react-hook-form
  • Flutter: Không cần thêm dependencies (sử dụng Form có sẵn)

Không cần cài đặt thủ công!

Sử dụng

Ví dụ cơ bản

tsx
import { useForm } from "react-hook-form"
import { Form, FormField, FormItem, FormLabel, FormControl, FormMessage } from "@/components/ui/form"
import { Input } from "@/components/ui/input"
import { Button } from "@/components/ui/button"

export default function FormDemo() {
  const form = useForm({
    defaultValues: {
      email: "",
    },
  })

  function onSubmit(values: { email: string }) {
    console.log(values)
  }

  return (
    <Form {...form}>
      <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
        <FormField
          control={form.control}
          name="email"
          render={({ field }) => (
            <FormItem>
              <FormLabel>Email</FormLabel>
              <FormControl>
                <Input type="email" placeholder="Nhập email của bạn" {...field} />
              </FormControl>
              <FormMessage />
            </FormItem>
          )}
        />
        <Button type="submit">Gửi</Button>
      </form>
    </Form>
  )
}
vue
<script setup lang="ts">
import { useForm } from 'vee-validate'
import { Form, FormField, FormItem, FormLabel, FormControl, FormMessage } from '@/components/ui/form'
import { Input } from '@/components/ui/input'
import { Button } from '@/components/ui/button'

const form = useForm({
  validationSchema: {
    email: (value: string) => {
      return value ? true : 'Email là bắt buộc'
    },
  },
})

function onSubmit(values: { email: string }) {
  console.log(values)
}
</script>

<template>
  <Form @submit="onSubmit">
    <FormField v-slot="{ field, errorMessage }" name="email">
      <FormItem>
        <FormLabel>Email</FormLabel>
        <FormControl>
          <Input type="email" placeholder="Nhập email của bạn" v-bind="field" />
        </FormControl>
        <FormMessage v-if="errorMessage">{{ errorMessage }}</FormMessage>
      </FormItem>
    </FormField>
    <Button type="submit">Gửi</Button>
  </Form>
</template>

Với Validation

tsx
import { useForm } from "react-hook-form"
import { zodResolver } from "@hookform/resolvers/zod"
import * as z from "zod"
import { Form, FormField, FormItem, FormLabel, FormControl, FormDescription, FormMessage } from "@/components/ui/form"
import { Input } from "@/components/ui/input"
import { Button } from "@/components/ui/button"

const formSchema = z.object({
  email: z.string().email("Email không hợp lệ"),
  username: z.string().min(2, "Tên đăng nhập phải có ít nhất 2 ký tự"),
})

export default function FormValidation() {
  const form = useForm<z.infer<typeof formSchema>>({
    resolver: zodResolver(formSchema),
    defaultValues: {
      email: "",
      username: "",
    },
  })

  function onSubmit(values: z.infer<typeof formSchema>) {
    console.log(values)
  }

  return (
    <Form {...form}>
      <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
        <FormField
          control={form.control}
          name="username"
          render={({ field }) => (
            <FormItem>
              <FormLabel>Tên đăng nhập</FormLabel>
              <FormControl>
                <Input placeholder="Nhập tên đăng nhập" {...field} />
              </FormControl>
              <FormDescription>Đây là tên đăng nhập công khai của bạn.</FormDescription>
              <FormMessage />
            </FormItem>
          )}
        />
        <FormField
          control={form.control}
          name="email"
          render={({ field }) => (
            <FormItem>
              <FormLabel>Email</FormLabel>
              <FormControl>
                <Input type="email" placeholder="Nhập email của bạn" {...field} />
              </FormControl>
              <FormMessage />
            </FormItem>
          )}
        />
        <Button type="submit">Gửi</Button>
      </form>
    </Form>
  )
}

API Reference

Components

ComponentDescriptionProps
FormContainer form chínhform, onSubmit, className / class
FormFieldWrapper field form với validationcontrol, name, render
FormItemWrapper item riêng lẻclassName / class
FormLabelLabel cho form controlhtmlFor, className / class
FormControlWrapper cho form controlclassName / class
FormDescriptionVăn bản trợ giúp bên dưới controlclassName / class
FormMessageHiển thị thông báo lỗiclassName / class

Accessibility

  • Keyboard Navigation: Tab qua các form fields, Enter để gửi
  • Screen Reader: Sử dụng <label>, aria-describedby, aria-invalid phù hợp
  • Error Handling: Thông báo lỗi rõ ràng với ARIA live regions
  • WCAG Compliance: Tuân thủ WCAG 2.1 Level AA

Author

Bùi Trọng Hiếu (kevinbui)

License

MIT © 2025 Bùi Trọng Hiếu (kevinbui)

Phát hành theo Giấy phép MIT.