Utility Components
InfoBlock, Divider, and Hidden — structural and utility components for forms
Overview
Utility components help structure forms without adding form fields. They provide visual separation, contextual information, and hidden data storage.
Full example
The complete sandbox example, read directly from the form-develop-app source at build time.
'use client'
import { Box, Code, Heading, HStack, Text, VStack } from '@chakra-ui/react'
import { Form } from '@letar/forms'
import { useState } from 'react'
import { z } from 'zod/v4'
import { DemoPageLayout } from '../_components'
const DemoSchema = z
.object({
firstName: z
.string()
.min(1, 'Обязательное')
.meta({ ui: { title: 'Имя' } }),
lastName: z
.string()
.min(1, 'Обязательное')
.meta({ ui: { title: 'Фамилия' } }),
email: z
.string()
.email()
.meta({ ui: { title: 'Email' } }),
phone: z
.string()
.optional()
.meta({ ui: { title: 'Телефон' } }),
type: z.enum(['individual', 'company']).meta({
ui: {
title: 'Тип клиента',
options: [
{ value: 'individual', label: 'Физлицо' },
{ value: 'company', label: 'Компания' },
],
},
}),
companyName: z
.string()
.optional()
.meta({ ui: { title: 'Название компании' } }),
inn: z
.string()
.optional()
.meta({ ui: { title: 'ИНН' } }),
utm_source: z.string().optional(),
referralCode: z.string().optional(),
})
.strip()
export default function UtilityDemoPage() {
const [submittedData, setSubmittedData] = useState<Record<string, unknown> | null>(null)
return (
<DemoPageLayout title="Утилитарные компоненты" description="Form.InfoBlock, Form.Divider, Form.Field.Hidden">
<VStack gap={6} align="stretch">
<Form
debug
schema={DemoSchema}
initialValue={{
firstName: '',
lastName: '',
email: '',
phone: '',
type: 'individual' as const,
companyName: '',
inn: '',
utm_source: '',
referralCode: '',
}}
onSubmit={(data) => setSubmittedData(data as Record<string, unknown>)}
>
{/* InfoBlock — информационный блок */}
<Heading size="md">Form.InfoBlock</Heading>
<Form.InfoBlock variant="info" title="Информация">
Заполните форму для регистрации. Все поля с * обязательны.
</Form.InfoBlock>
<Form.InfoBlock variant="warning">Данные нельзя изменить после отправки.</Form.InfoBlock>
<Form.InfoBlock variant="success" title="Успех">
Ваша скидка 10% будет применена автоматически.
</Form.InfoBlock>
<Form.InfoBlock variant="error">Сервис временно недоступен. Попробуйте позже.</Form.InfoBlock>
<Form.InfoBlock variant="tip" title="Совет">
Используйте корпоративный email для быстрой верификации.
</Form.InfoBlock>
{/* Divider — разделитель */}
<Heading size="md" mt={4}>
Form.Divider
</Heading>
<Form.Divider label="Персональные данные" />
<HStack gap={4}>
<Form.Field.String name="firstName" />
<Form.Field.String name="lastName" />
</HStack>
<Form.Divider label="Контактные данные" />
<Form.Field.String name="email" />
<Form.Field.String name="phone" />
<Form.Divider />
<Form.Field.Select name="type" />
{/* InfoBlock с условным рендерингом */}
<Form.When field="type" is="company">
<Form.InfoBlock variant="warning">Для компаний требуется ИНН.</Form.InfoBlock>
<Form.Field.String name="companyName" />
<Form.Field.String name="inn" />
</Form.When>
<Form.Divider variant="dashed" label="Системные данные" />
{/* Hidden — скрытые поля */}
<Heading size="md">Form.Field.Hidden</Heading>
<Text fontSize="sm" color="fg.muted">
Скрытые поля не рендерятся в DOM, но передаются при отправке. Проверьте значения в DebugValues внизу.
</Text>
<Form.Field.Hidden name="utm_source" value="demo-page" />
<Form.Field.Hidden name="referralCode" value="PARTNER2026" />
<Box p={3} bg="bg.subtle" borderRadius="md">
<Code>Form.Field.Hidden name="utm_source" value="demo-page"</Code>
<br />
<Code>Form.Field.Hidden name="referralCode" value="PARTNER2026"</Code>
</Box>
<Form.Button.Submit>Отправить</Form.Button.Submit>
</Form>
{submittedData && (
<Box p={4} bg="green.subtle" borderRadius="md">
<Heading size="sm" mb={2}>
Отправленные данные:
</Heading>
<Code whiteSpace="pre" display="block">
{JSON.stringify(submittedData, null, 2)}
</Code>
</Box>
)}
</VStack>
</DemoPageLayout>
)
}shadcn-вариант этого примера ещё не готов.
Vue-пример для этого поля появится позже.
Angular-пример для этого поля появится позже.
| Component | Purpose |
|---|---|
Form.InfoBlock | Info/warning/error/success/tip message block |
Form.Divider | Horizontal separator with optional label |
Form.Field.Hidden | Hidden field (not rendered, only in form state) |
Form.InfoBlock
Displays contextual messages inside forms. Based on Chakra UI Alert.
<Form.InfoBlock variant="info" title="Note">
Fill in all fields to receive a 10% discount.
</Form.InfoBlock>Variants
| Variant | Color | Use case |
|---|---|---|
info (default) | Blue | General information |
warning | Orange | Caution, requirements |
error | Red | Critical issues |
success | Green | Confirmations |
tip | Teal | Helpful hints |
Props
| Prop | Type | Default | Description |
|---|---|---|---|
variant | 'info' | 'warning' | 'error' | 'success' | 'tip' | 'info' | Visual style |
title | ReactNode | — | Block heading |
children | ReactNode | — | Content |
appearance | 'subtle' | 'surface' | 'outline' | 'solid' | 'subtle' | Chakra Alert visual variant |
size | 'sm' | 'md' | 'lg' | 'md' | Size |
Conditional InfoBlock
Combine with Form.When for dynamic messages:
<Form.When field="type" is="company">
<Form.InfoBlock variant="warning">Company registration requires TIN and legal address.</Form.InfoBlock>
</Form.When>Form.Divider
Horizontal separator for grouping form sections. Based on Chakra UI Separator.
<Form.Field.String name="firstName" />
<Form.Field.String name="lastName" />
<Form.Divider label="Contact Information" />
<Form.Field.String name="email" />
<Form.Field.String name="phone" />With icon
import { LuPhone } from 'react-icons/lu'
;<Form.Divider label="Phone Numbers" icon={<LuPhone />} />Props
| Prop | Type | Default | Description |
|---|---|---|---|
label | ReactNode | — | Text label in the middle |
icon | ReactNode | — | Icon before label |
variant | 'solid' | 'dashed' | 'dotted' | 'solid' | Line style |
size | 'xs' | 'sm' | 'md' | 'lg' | 'xs' | Line thickness |
colorPalette | string | 'gray' | Color palette |
Without label
A simple horizontal line:
<Form.Divider />Hidden
API: Form.Field.Hidden
Stores data in form state without rendering anything in the DOM. Useful for UTM parameters, referral codes, internal IDs.
<Form.Field.Hidden name="utm_source" value={searchParams.get('utm_source')} />
<Form.Field.Hidden name="referralCode" value="PARTNER2026" />Props
| Prop | Type | Description |
|---|---|---|
name | string | Field name in the form |
value | unknown | Value to set (syncs on change) |
Dynamic value
The value is synced reactively — when the value prop changes, the form state updates:
const [geo, setGeo] = useState(null)
useEffect(() => { detectLocation().then(setGeo) }, [])
<Form.Field.Hidden name="location" value={geo} />Accessing in form submission
Hidden fields are included in the submitted data just like any other field:
<Form
onSubmit={(data) => {
console.log(data.utm_source) // "google"
console.log(data.referralCode) // "PARTNER2026"
}}
>
<Form.Field.String name="email" />
<Form.Field.Hidden name="utm_source" value="google" />
<Form.Field.Hidden name="referralCode" value="PARTNER2026" />
<Form.Button.Submit />
</Form>Complete Example
<Form schema={Schema} initialValue={data} onSubmit={save}>
<Form.InfoBlock variant="info" title="Registration">
Please fill in all required fields.
</Form.InfoBlock>
<Form.Divider label="Personal Details" />
<Form.Field.String name="firstName" />
<Form.Field.String name="lastName" />
<Form.Divider label="Contact" />
<Form.Field.String name="email" />
<Form.Field.String name="phone" />
<Form.When field="isPremium" is={true}>
<Form.InfoBlock variant="success">Premium benefits are active!</Form.InfoBlock>
</Form.When>
<Form.Field.Hidden name="utm_source" value="landing" />
<Form.Field.Hidden name="formVersion" value="2.0" />
<Form.Button.Submit>Register</Form.Button.Submit>
</Form>Live Example
Try the interactive example on forms-example.letar.best.