Section

A titled group of fields, rendered as a fieldset.

Contact
Address

Where we send the invoice.

Installation

npx shadcn@latest add @formdef/section

Register it in the section structure slot in lib/formdef/index.tsx, as structure: { section: Section }. From then on every { section } entry of a layout renders through it.

Usage

export const  = createForm({
  : .({ : .(), : .(), : .() }),
  : { : '', : '', : '' },
  fields: {
    name: { : 'text', : { : 'Name' } },
    street: { : 'text', : { : 'Street' } },
    city: { : 'text', : { : 'City' } },
  },
  : [
    'name',
    {
      : 'Delivery address',
      : ['street', 'city'],
      : { : 'Where the parcel goes.' },
    },
  ],
})

The section renders a <fieldset>. Its <legend> is the entry's title, and a description sits below it, tied to the fieldset with aria-describedby. For a section inside another one, variant: 'label' sets the legend in the size of a field label.

Layout describes sections, rows and the other layout entries.

Props

Prop

Type

Source

'use client'

import type { SectionProps } from '@formdef/core'
import { type ComponentProps, useId } from 'react'

import { FieldDescription, FieldGroup, FieldLegend, FieldSet } from '@/components/ui/field'

type LegendVariant = NonNullable<ComponentProps<typeof FieldLegend>['variant']>

type SectionFrameProps = SectionProps &
  Pick<ComponentProps<typeof FieldSet>, 'className'> & {
    description?: string | undefined
    variant?: LegendVariant | undefined
  }

export const Section = ({
  label,
  description,
  variant = 'legend',
  className,
  children,
}: SectionFrameProps) => {
  const descriptionId = useId()
  const hasDescription = description !== undefined && description !== ''

  return (
    <FieldSet className={className} aria-describedby={hasDescription ? descriptionId : undefined}>
      <FieldLegend variant={variant}>{label}</FieldLegend>
      {hasDescription && <FieldDescription id={descriptionId}>{description}</FieldDescription>}
      <FieldGroup>{children}</FieldGroup>
    </FieldSet>
  )
}