# Form

O `<form>` e o contexto do React Hook Form numa peça só, para o `FormField`
achar o `control` sozinho. Vive em `@rivocode/ui/form`.

Vai com `noValidate`: quem valida e o schema, e o balao nativo do navegador
apareceria em ingles, fora do tema e antes da nossa mensagem.

O `onSubmit` recebe os valores já validados e convertidos. Use com o
`useZodForm`, que liga o resolver e separa o tipo de entrada do de saída.

## No React Native

Traduz, no caminho próprio `@rivocode/ui-native/form`, com o mesmo arranjo do web e pela mesma razão: o `react-hook-form` é peer opcional. O `useZodForm` é idêntico, linha por linha, porque não há navegador nele.

**O que muda é quem dispara o envio.** No React Native não existe `<form>`, não existe `type="submit"` e não existe Enter que envie: nada é implícito. Então o `Form` entrega o envio a quem desenha o botão (`children` pode ser uma função que recebe `{ submit, isSubmitting }`), e continua aceitando JSX comum para quando o botão mora fora, numa barra fixa no rodapé da tela.

**E muda a ponte com o controle.** No web o `Field` da Base UI liga rótulo, ajuda e erro a qualquer controle que esteja dentro, pelo contexto; aqui não há contexto nenhum: o `Field` nativo desenha um `Text` em cima e outro embaixo, e o controle do meio não fica sabendo de nada. Por isso o campo que o `FormField` entrega leva duas coisas a mais, `accessibilityLabel` e `invalid`, e os adaptadores as põem no controle: sem isso, um `TextInput` sob um rótulo fica **sem nome nenhum** para o leitor de tela. O `label` do `FormField` é obrigatório aqui pela mesma razão.

Os adaptadores são quatro. `forValue`, `forChecked` e `forDate` têm o nome e o trabalho do web. O `forDate` agora converte o vazio para `null` e fala ISO, que é o que o `DatePicker` e o `DateRangePicker` nativos pedem. O quarto é só daqui: `forText`, para `Input` e `Textarea`, porque o `TextInput` chama `onChangeText` com a string crua e não com um evento: espalhar o campo nele guardaria no formulário um objeto de evento que não existe. Ele leva o `ref` junto, e aí o `form.setFocus()` funciona de verdade: `TextInput` tem `focus()`.

## Importação

```tsx
import { Form } from '@rivocode/ui/form'
```

## Exemplos

### Emitir nota

```tsx
import { Button, DatePicker, Input } from '@rivocode/ui'
import { Form, FormField, forDate, useZodForm } from '@rivocode/ui/form'
import { z } from 'zod'

const schema = z.object({
  email: z.email('Escreva um email valido'),
  dueAt: z.date('Escolha a data'),
})

export function IssueInvoice() {
  const form = useZodForm(schema, {
    defaultValues: { email: 'financeiro@rivocode.com', dueAt: new Date(2026, 2, 3) },
  })

  return (
    <div className="w-80">
      <Form form={form} onSubmit={() => {}}>
        <FormField name="email" label="E-mail" description="Para onde vai a nota">
          {(field) => <Input {...field} placeholder="você@empresa.com" />}
        </FormField>

        <FormField name="dueAt" label="Vencimento">
          {(field) => <DatePicker {...forDate(field)} />}
        </FormField>

        <Button type="submit" className="self-start">
          Emitir
        </Button>
      </Form>
    </div>
  )
}
```

## Props

| Prop | Tipo | Obrigatória | Desde | O que faz |
| --- | --- | --- | --- | --- |
| `form` | `UseFormReturn<Entry, unknown, Saida>` | sim | 0.4.0 | O retorno do `useZodForm` ou do `useForm`. |
| `onSubmit` | `SubmitHandler<Saida>` | sim | 0.4.0 | Chamado com os valores ja validados e convertidos pelo schema. |

Além dessas: repassa `className`, `style`, `id` e os demais atributos do elemento raiz.

## Partes

O componente se monta com as peças abaixo. Todas vêm de `@rivocode/ui/form`.

### FormField

Uma linha de formulário inteira: rótulo, controle, ajuda e erro, ligados entre
si. Vive em `@rivocode/ui/form`.

O controle vem por funcao, e não por clonagem do filho, porque cada controle do
catalogo recebe valor de um jeito e adivinhar qual falha na tela, não no tipo:

```tsx
<FormField name="email" label="E-mail">
  {(campo) => <Input {...campo} />}
</FormField>
```

Para `Input` e `Textarea`, espalhar o campo basta. Para `Select`, `Checkbox` e
`DatePicker`, os adaptadores fazem a ponte.

Ele não inventa `id` nenhum: quem liga o rótulo ao controle e o `Field` da Base
UI, pelo contexto.

| Prop | Tipo | Obrigatória | Desde | O que faz |
| --- | --- | --- | --- | --- |
| `name` | `Name` | sim | 0.4.0 | O caminho do campo no schema. |
| `control` | `Control<Values>` |  | 0.4.0 | So quando o campo vive fora de um `<Form>`. |
| `description` | `ReactNode` |  | 0.4.0 |  |
| `label` | `ReactNode` |  | 0.4.0 |  |

## Ver também

- [Autocomplete](/componentes/autocomplete.md)
- [Calendar](/componentes/calendar.md)
- [Checkbox](/componentes/checkbox.md)
- [CheckboxGroup](/componentes/checkbox-group.md)
- [ColorPicker](/componentes/color-picker.md)
- [Combobox](/componentes/combobox.md)
- [Convenções da biblioteca](/convencoes.md): Provider, tokens e as regras que valem para toda peça
- [Índice completo](/llms.txt)
