Fieldset
A component that groups a legend, helper, and error text, ensuring accessibility.
import { OctagonAlertIcon } from 'lucide-react'
import { Field } from '~/components/ui/field'
import { Fieldset } from '~/components/ui/fieldset'
import { Icon } from '~/components/ui/icon'
import { Switch } from '~/components/ui/switch'
export const Demo = (props: Fieldset.RootProps) => {
  return (
    <Fieldset.Root {...props}>
      <Fieldset.Legend>Notifiations</Fieldset.Legend>
      <Fieldset.HelperText>Get notifcations when your are not online</Fieldset.HelperText>
      <Fieldset.Control>
        <Field.Root>
          <Switch size="sm" defaultChecked>
            Comments
          </Switch>
          <Field.HelperText>When someone posts a comment</Field.HelperText>
        </Field.Root>
        <Field.Root>
          <Switch size="sm" defaultChecked>
            Candidates
          </Switch>
          <Field.HelperText>When someone applies for a job</Field.HelperText>
        </Field.Root>
      </Fieldset.Control>
      <Fieldset.ErrorText>
        <Icon size="sm">
          <OctagonAlertIcon />
        </Icon>
        Something went wrong
      </Fieldset.ErrorText>
    </Fieldset.Root>
  )
}
Usage
import { Fieldset } from '~/components/ui/fieldset'Examples
Invalid
Use the invalid prop to indicate that the fieldset is invalid.
<Fieldset.Root invalid>
  <Fieldset.Legend>Notifiations</Fieldset.Legend>
  <Fieldset.HelperText>Get notifcations when your are not online</Fieldset.HelperText>
  <Fieldset.Control>
    <Field.Root>
      <Switch size="sm">Comments</Switch>
      <Field.HelperText>When someone posts a comment</Field.HelperText>
    </Field.Root>
  </Fieldset.Control>
  <Fieldset.ErrorText>
    <Icon size="sm">
      <OctagonAlertIcon />
    </Icon>
    Something went wrong
  </Fieldset.ErrorText>
</Fieldset.Root>Installation
npx @park-ui/cli components add fieldset1
Add Styled Primitive
Copy the code snippet below into ~/components/ui/styled/fieldset.tsx
'use client'
import type { Assign, PolymorphicProps } from '@ark-ui/react'
import { ark } from '@ark-ui/react/factory'
import { Fieldset } from '@ark-ui/react/fieldset'
import { type FieldsetVariantProps, fieldset } from 'styled-system/recipes'
import type { ComponentProps, HTMLStyledProps } from 'styled-system/types'
import { createStyleContext } from './utils/create-style-context'
const { withProvider, withContext } = createStyleContext(fieldset)
export type RootProviderProps = ComponentProps<typeof RootProvider>
export const RootProvider = withProvider<
  HTMLFieldSetElement,
  Assign<Assign<HTMLStyledProps<'fieldset'>, Fieldset.RootProviderBaseProps>, FieldsetVariantProps>
>(Fieldset.Root, 'root')
export type RootProps = ComponentProps<typeof Root>
export const Root = withProvider<
  HTMLFieldSetElement,
  Assign<Assign<HTMLStyledProps<'fieldset'>, Fieldset.RootBaseProps>, FieldsetVariantProps>
>(Fieldset.Root, 'root')
export const ErrorText = withContext<
  HTMLSpanElement,
  Assign<HTMLStyledProps<'span'>, Fieldset.ErrorTextBaseProps>
>(Fieldset.ErrorText, 'errorText')
export const HelperText = withContext<
  HTMLSpanElement,
  Assign<HTMLStyledProps<'span'>, Fieldset.HelperTextBaseProps>
>(Fieldset.HelperText, 'helperText')
export const Legend = withContext<
  HTMLLegendElement,
  Assign<HTMLStyledProps<'legend'>, Fieldset.LegendBaseProps>
>(Fieldset.Legend, 'legend')
export const Control = withContext<
  HTMLDivElement,
  Assign<HTMLStyledProps<'div'>, PolymorphicProps>
>(ark.div, 'control')
export { FieldsetContext as Context } from '@ark-ui/react/fieldset'
No snippet foundNo snippet found2
Add Re-Export
To improve the developer experience, re-export the styled primitives in~/components/ui/fieldset.tsx.
export * as Fieldset from './styled/fieldset'
3
Integrate Recipe
If you're not using @park-ui/preset, add the following recipe to yourpanda.config.ts:
import { fieldsetAnatomy } from '@ark-ui/anatomy'
import { defineSlotRecipe } from '@pandacss/dev'
export const fieldset = defineSlotRecipe({
  className: 'fieldset',
  slots: [...fieldsetAnatomy.keys(), 'control'],
  base: {
    root: {
      display: 'grid',
      borderTopWidth: '1px',
      py: '6',
      columnGap: '8',
      rowGap: '1.5',
      gridTemplateAreas: {
        base: `
        "legend legend" 
        "helperText helperText"
        "control control"
        "errorText errorText"
        `,
        md: `
        "legend control"
        "helperText control"
        "errorText errorText"`,
      },
      gridTemplateRows: 'auto 1fr',
      gridTemplateColumns: '1fr auto',
      width: 'full',
    },
    control: {
      gridArea: 'control',
      display: 'grid',
      gap: '4',
    },
    legend: {
      color: 'fg.default',
      fontWeight: 'medium',
      gridArea: 'legend',
      textStyle: 'sm',
      float: 'left',
      '+ *': {
        clear: 'both',
      },
      _disabled: {
        color: 'fg.disabled',
      },
    },
    helperText: {
      color: 'fg.muted',
      gridArea: 'helperText',
      textStyle: 'sm',
      _disabled: {
        color: 'fg.disabled',
      },
    },
    errorText: {
      alignItems: 'center',
      color: 'fg.error',
      display: 'inline-flex',
      gap: '2',
      gridArea: 'errorText',
      mt: '4',
      textStyle: 'sm',
      _disabled: {
        color: 'fg.disabled',
      },
    },
  },
})