/** Data Entry component prop types — @see docs/COMPONENTS.md#data-entry */ import type { RenderProps as InputOTPRenderProps } from "input-otp"; import type { DayPickerProps } from "react-day-picker"; import type { DateRange } from "react-day-picker"; import type * as React from "react"; import type { UploadFileItem } from "../../components/data-entry/upload-types.js"; import type { FieldA11yProps } from "../../lib/field-a11y.js"; import type { ClassNameProp, ControlWidthProp, DisabledProp, EmptyMessageProp, ErrorBagProp, ErrorProp, HelperProp, IdProp, LabelProp, NameProp, OnValueChangeProp, OnSearchChangeProp, OpenProp, OnOpenChangeProp, PlaceholderProp, RequiredProp, ValueProp, DefaultValueProp, FormLayoutProp, WidthProp, BreakpointProp, DensityProp, SizeProp, TitleProp, DefaultOpenProp, ControlStatusProp, ControlVariantProp, AllowClearProp, MaxTagCountProp, MaxTagPlaceholderProp, NotFoundContentProp, PopupMatchWidthProp, PendingProp, PadProp, PadRawProp } from "../vocabulary/index.js"; import type { ResponsiveGridColumnsProp } from "./layout.prop.js"; /** One-outline-per-group appearance for the compound InputOTP control. */ export type InputOTPGroupAppearanceProp = "slots" | "grouped"; /** @see InputOTPGroup */ export type InputOTPGroupProp = React.HTMLAttributes & { appearance?: InputOTPGroupAppearanceProp; }; /** * Main-axis alignment of the whole code row (groups + separators) inside its container. * `start` is the historical default. A centred challenge is the common auth case and used to * force every consumer to wrap `.ui-otp-container` in their own flex-centring div. * @see InputOTP */ export type InputOTPAlignProp = "start" | "center" | "end"; /** * antd `Input.OTP mask`. `true` paints every filled slot as `•`; a STRING uses that character * instead. Only the PAINT changes — the real code stays in the field's value, so submission, * `onChange` and the accessible value are untouched (a mask that ate the value would be a bug, * not a privacy feature). */ export type InputOTPMaskProp = boolean | string; /** * @see InputOTP — the one-time-code field. A passthrough of `input-otp`'s `OTPInput` (the hidden * real `` that owns paste, caret and arrow-key behaviour) plus this library's control-surface * axes, so a code field lines up with the `Input`/`Select` beside it in a form row. * * The value is ALWAYS driven from here (`value` controlled, or `defaultValue` + internal state), so * `formatter` and `readOnly` hold for typing AND for paste — `input-otp` writes its own internal * state on paste, which a wrapper that only intercepted `onChange` could not undo. * * `style` is OMITTED because it cannot be honoured: `input-otp` owns both elements it could land * on and writes their geometry itself — the field's own style object replaces anything passed in * (measured: `style={{ color: "red" }}` left the input at the library's `color: transparent`) and * the container's is hard-coded too. A type that accepts a prop the render can never deliver is * the defect gh#477 reported for `id`; `id` is real and forwarded, this one was not. The paint of * the field is reached through `className` / `containerClassName` and the `--otp-*` tokens. */ export type InputOTPProp = Omit, "value" | "defaultValue" | "onChange" | "size" | "children" | "style"> & { /** Number of slots — antd `length`. Required by `input-otp`. */ maxLength: number; value?: string; /** Uncontrolled seed — the field then owns its own value. */ defaultValue?: string; /** Controlled-vocabulary change handler; receives the bare code, never an event. */ onValueChange?: (value: string) => void; /** `input-otp`'s own name for the same callback — kept for the existing call sites. */ onChange?: (value: string) => void; /** Fires once the last slot is filled (auto-submit). */ onComplete?: (value: string) => void; /** * antd `Input.OTP formatter` — normalise every code the field accepts (upper-case, strip spaces). * Runs AFTER `pattern`, which `input-otp` matches against the raw keystroke: a pattern must * therefore accept what the user actually types, not only what the formatter produces. */ formatter?: (value: string) => string; /** antd `Input.OTP mask` — paint only; the real code stays in the value. */ mask?: InputOTPMaskProp; /** Main-axis alignment of the whole code row. */ align?: InputOTPAlignProp; /** Control height tier — the shared `--control-height` ladder, as on every other field. */ size?: SizeProp; /** Validation state the field paints — antd `status`. `error` also reports `aria-invalid`. */ status?: ControlStatusProp; /** Chrome level — antd `variant`. Default `outlined`. */ variant?: ControlVariantProp; /** Regex source (or literal) every accepted value must match — `input-otp`'s `pattern`. */ pattern?: string; /** Rewrite pasted text before it reaches the field — `input-otp`'s `pasteTransformer`. */ pasteTransformer?: (pasted: string) => string; /** Class on the row container that `input-otp` renders (the slots' flex parent). */ containerClassName?: ClassNameProp; /** Password-manager badge avoidance strategy — `input-otp`'s own escape hatch. */ pushPasswordManagerStrategy?: "increase-width" | "none"; /** No-JS fallback stylesheet emitted by `input-otp`; `null` disables it. */ noScriptCSSFallback?: string | null; /** CSP nonce for the stylesheet `input-otp` injects. */ nonce?: string; /** The slot tree (`InputOTPGroup` > `InputOTPSlot`) — the normal API. */ children?: React.ReactNode; /** `input-otp`'s headless escape hatch: render the whole row yourself from the slot state. */ render?: (props: InputOTPRenderProps) => React.ReactNode; }; /** * Character-counter configuration shared by `Input` and `Textarea` — Ant Design's `count` * (`@rc-component/input`'s `CountConfig`). * * antd's `exceedFormatter` is deliberately absent: it rewrites the field's text while the user is * still typing, which in Japanese truncates a live IME conversion. The counter here REPORTS an * overrun (`data-exceeded` on the counter element) and never edits the value. */ export type ControlCountProp = { /** Ceiling reported by the counter. Displayed, never enforced — see the note above. */ max?: number; /** Render the counter. Default `true` whenever `count` is given at all. */ show?: boolean; /** Replaces the whole counter text. */ formatter?: (info: { value: string; count: number; max?: number; }) => React.ReactNode; /** * How a character is counted. The default counts CODE POINTS, not UTF-16 units, so one emoji * and one 全角 kanji each count as one. Pass `(v) => v.length` for native `maxLength` semantics. */ strategy?: (value: string) => number; }; /** @see Input */ /** `Command` — the library's own knob; cmdk's root props pass through untouched beside it. */ export type CommandProp = { /** * antd `List` `split`: draw the list as ONE ruled box — group padding 0, rows full-bleed to the * panel edge with a square highlight, a hairline `border-block-end` between rows and none after * the last visible one. For option / checkbox lists (filter facets, pickers). Default `false`: * a command palette keeps its airy, inset rows. */ split?: boolean; }; export type InputProp = Omit, "size" | "prefix"> & { onValueChange?: (value: string) => void; /** * Control height tier: `md` (default), plus `xs`, `sm` and `lg` — the same tiers as * SelectTrigger and NumberInput. * * `xs` was missing from this union alone. Everything underneath it already worked: `Input` * renders `ui-control` and emits `data-size={size}`, and `.ui-control[data-size="xs"]` * (src/styles/control.css:1674) binds `--control-height-xs`. That rule was added for the * select family — its comment says the token "existed with nothing reading it" — and this * union was never widened to match, so the most-used control in the package was the one * control missing the bottom rung, for a reason no user could have guessed from behaviour. */ size?: "xs" | "sm" | "md" | "lg"; /** Validation state the field paints — antd `status`. `error` also reports `aria-invalid`. */ status?: ControlStatusProp; /** Chrome level — antd `variant`. Default `outlined`. */ variant?: ControlVariantProp; /** * antd `allowClear` — show an inline ✕ that clears the field while it holds text (default * false). The OBJECT form additionally replaces the icon and/or the accessible label. */ allowClear?: AllowClearProp; /** Called after the field is cleared via the inline ✕. */ onClear?: () => void; /** A leading affordance pinned inside the start of the field (e.g. a mail/lock icon). */ leadingIcon?: React.ReactNode; /** A trailing affordance pinned inside the end of the field (replaced by the clear ✕ when `allowClear` + value). */ trailingIcon?: React.ReactNode; /** antd `prefix` — content pinned INSIDE the start of the field (¥, a unit, a small glyph). */ prefix?: React.ReactNode; /** antd `suffix` — content pinned INSIDE the end of the field (%, 円, a hint glyph). */ suffix?: React.ReactNode; /** antd `addonBefore` — a segment welded OUTSIDE the start of the box (`https://`, a currency). */ addonBefore?: React.ReactNode; /** antd `addonAfter` — a segment welded OUTSIDE the end of the box (`.com`, a unit, a button). */ addonAfter?: React.ReactNode; /** Character counter — antd `count`. */ count?: ControlCountProp; }; /** @see Textarea */ export type TextareaProp = React.TextareaHTMLAttributes & { onValueChange?: (value: string) => void; pad?: PadProp; padRaw?: PadRawProp; /** * antd `allowClear` — an inline ✕ (top-end) that clears the field while it holds text (default * false). The OBJECT form additionally replaces the icon and/or the accessible label. */ allowClear?: AllowClearProp; /** Called after the field is cleared via the inline ✕. */ onClear?: () => void; /** * Chrome level. `outlined` (default) / `filled` / `borderless` are antd's `variant`; `default` * and `ghost` are this library's older spellings of the first and the last, still accepted. */ variant?: ControlVariantProp | "default" | "ghost"; /** Validation state the field paints — antd `status`. `error` also reports `aria-invalid`. */ status?: ControlStatusProp; /** Control height tier: `md` (default), `sm` or `lg`. */ size?: "sm" | "md" | "lg"; autoGrow?: boolean; /** * antd `autoSize`. `true` is `autoGrow`; an object also carries the row bounds, so * `autoSize={{ minRows: 2, maxRows: 6 }}` is `autoGrow minRows={2} maxRows={6}`. */ autoSize?: boolean | { minRows?: number; maxRows?: number; }; /** Floor in text rows while `autoGrow`; never undercuts the `--control-height` tier. */ minRows?: number; /** Ceiling in text rows while `autoGrow` — past it the control scrolls internally. `0` = unbounded. */ maxRows?: number; /** Character counter — antd `count`. */ count?: ControlCountProp; }; /** * @see NumberInput — localized numeric spinbutton (composes `Input` + step `Button`s). * `value`/`defaultValue`/`onValueChange` carry a `number | null` (null = empty). `step` drives both * the stepper buttons and ArrowUp/ArrowDown (Shift = ×10); `precision` sets the committed decimal * places (inferred from `step` when omitted). Value commits clamped to `min`/`max` on blur/Enter. */ export type NumberInputProp = FieldA11yProps & { value?: ValueProp; defaultValue?: DefaultValueProp; onValueChange?: OnValueChangeProp; /** Lower bound — clamps the committed value and disables the decrement stepper at the floor. */ min?: number; /** Upper bound — clamps the committed value and disables the increment stepper at the ceiling. */ max?: number; /** Increment for the steppers + ArrowUp/ArrowDown (Shift = ×10). Default 1. */ step?: number; /** Committed decimal places. Inferred from `step` when omitted. */ precision?: number; /** * antd `formatter` — how the committed number is DISPLAYED at rest (thousands separators, a * unit). Replaces the built-in `Intl.NumberFormat`; pair it with `parser`, or the text it * produces cannot be read back. */ formatter?: (value: number | null) => string; /** antd `parser` — turns the displayed text back into a number. The inverse of `formatter`. */ parser?: (display: string) => number | null; /** antd `keyboard` — ArrowUp/ArrowDown step the value. Default `true`. */ keyboard?: boolean; /** antd `changeOnWheel` — a mouse wheel over the FOCUSED field steps the value. Default `false`. */ changeOnWheel?: boolean; /** antd `controls` — show the increment/decrement steppers. Default `true`. */ controls?: boolean; /** Validation state the field paints — antd `status`. `error` also reports `aria-invalid`. */ status?: ControlStatusProp; /** Chrome level — antd `variant`. Default `outlined`. */ variant?: ControlVariantProp; disabled?: DisabledProp; /** Read-only: value is shown and selectable but neither typeable nor steppable. */ readOnly?: boolean; size?: SizeProp; placeholder?: PlaceholderProp; /** Leading affix inside the field (e.g. `¥`). */ prefix?: React.ReactNode; /** Trailing affix inside the field (e.g. `%`). */ suffix?: React.ReactNode; /** Form field name — the visible input submits its value natively. */ name?: NameProp; id?: IdProp; className?: ClassNameProp; "data-testid"?: string; }; /** * @see Form — layout context for FormFields (Ant-style). `layout`/`labelWidth`/`controlWidth`/ * `labelAlign` are applied to every FormField and overridable per field. `collapseBelow` sets the * breakpoint at which `horizontal` collapses to `vertical` (mobile-first; `false` = always * horizontal). `columns` lays fields out in a responsive grid (reuses ResponsiveGrid). */ export type FormProp = React.FormHTMLAttributes & { disabled?: boolean; requiredMark?: boolean | "optional"; layout?: FormLayoutProp; labelWidth?: WidthProp; controlWidth?: WidthProp; labelAlign?: "start" | "end"; collapseBelow?: BreakpointProp | false; columns?: ResponsiveGridColumnsProp; density?: DensityProp; /** Server validation error bag (e.g. Inertia's `form.errors`). */ errors?: ErrorBagProp; /** * Render the caller's own element instead of a `
`, keeping only the layout context. For * routing libraries that own the form element (Inertia, TanStack Form) — two `` elements * cannot nest. */ asChild?: boolean; className?: ClassNameProp; }; /** * @see FormField — exactly one of `children` (an interactive control) or `staticText`: * a read-only VALUE row inside the same Form, styled to match `Descriptions.Item`'s value * typography (`text-sm break-all`) byte-for-byte. This is the "mixed read-only + editable fields * on one form" case (an immutable name/email row above an editable role Select, for example) — * putting the read-only rows through FormField itself, not a separate `Descriptions` composed * alongside it, gets perfect layout/labelAlign/row-gap sync FOR FREE because it IS the same * component reading the same Form context, rather than two components whose contracts need * reconciling. `staticText` skips FormField's control a11y wiring (id/aria-labelledby/ * aria-describedby cloning) entirely — there is no real control to label, so none of that applies. */ export type FormFieldProp = { /** Optional — auto-generated and injected into the child control when omitted. */ id?: IdProp; /** * Error-bag key of this field. When the surrounding `Form` carries `errors`, the field * resolves its message from `errors[name]` automatically (an explicit `error` prop wins) and * CLAIMS the key so `` does not repeat it. */ name?: NameProp; /** * Rendered on the control as `data-field`, and as a native `name` when the app opted in via * ``. Defaults to `name`, then `id` — which is why an app whose * fields already carry a column-named `id` gets the attribute on every control without * editing a single screen. */ field?: NameProp; label: LabelProp; required?: RequiredProp; helper?: HelperProp; /** * Which side of the control the helper line sits on — `after` (default, under the input) or * `before` (between the label and the input). * * `before` is for a helper the reader needs BEFORE they answer rather than after: the * secondary language of a bilingual form, a unit or format note, a pick-one-of-these * preamble. `labelAddon` cannot carry that — it belongs to the label row, sized for a chip, a * help button or a short text action; in a horizontal/inline field it wraps under the label * inside the label column, so a full sentence stacks there instead of above the input. Putting the second line inside `label` does work, but costs the * string-label fallbacks (`aria-label`, `FieldNameContext`), which fire only when `label` is * a plain string. * * Paint only: the helper keeps its id and stays on the control's `aria-describedby`, so this * never changes what a screen reader reads or the order it reads it in. */ helperPlacement?: "before" | "after"; error?: ErrorProp; validateStatus?: "success" | "warning" | "error" | "validating"; hasFeedback?: boolean; feedback?: React.ReactNode; /** * Optional control rendered after the label (e.g. a help button, a short text action). In a * horizontal/inline field the label row wraps: an addon that does not fit beside the label * drops to its own line under it, capped to the label column, never into the control column. */ labelAddon?: React.ReactNode; /** Override the Form's layout for this field only. */ layout?: FormLayoutProp; /** Override the Form's label width for this field (horizontal layout). */ labelWidth?: WidthProp; /** Override the Form's control width for this field. */ controlWidth?: WidthProp; /** Span N columns when inside a `columns` Form grid. */ colSpan?: number; className?: ClassNameProp; children: React.ReactNode; staticText?: never; } | { /** Optional — auto-generated and injected into the child control when omitted. */ id?: IdProp; /** * Error-bag key of this field. When the surrounding `Form` carries `errors`, the field * resolves its message from `errors[name]` automatically (an explicit `error` prop wins) * and CLAIMS the key so `` does not repeat it. */ name?: NameProp; /** Stable machine key — see the `children` variant above. Unused on a read-only row. */ field?: NameProp; label: LabelProp; required?: RequiredProp; helper?: HelperProp; /** * Which side of the control the helper line sits on — `after` (default, under the input) or * `before` (between the label and the input). * * `before` is for a helper the reader needs BEFORE they answer rather than after: the * secondary language of a bilingual form, a unit or format note, a pick-one-of-these * preamble. `labelAddon` cannot carry that — it belongs to the label row, sized for a chip, a * help button or a short text action; in a horizontal/inline field it wraps under the label * inside the label column, so a full sentence stacks there instead of above the input. Putting the second line inside `label` does work, but costs the * string-label fallbacks (`aria-label`, `FieldNameContext`), which fire only when `label` is * a plain string. * * Paint only: the helper keeps its id and stays on the control's `aria-describedby`, so this * never changes what a screen reader reads or the order it reads it in. */ helperPlacement?: "before" | "after"; error?: ErrorProp; validateStatus?: "success" | "warning" | "error" | "validating"; hasFeedback?: boolean; feedback?: React.ReactNode; /** * Optional control rendered after the label (e.g. a help button, a short text action). In a * horizontal/inline field the label row wraps: an addon that does not fit beside the label * drops to its own line under it, capped to the label column, never into the control column. */ labelAddon?: React.ReactNode; /** Override the Form's layout for this field only. */ layout?: FormLayoutProp; /** Override the Form's label width for this field (horizontal layout). */ labelWidth?: WidthProp; /** Override the Form's control width for this field. */ controlWidth?: WidthProp; /** Span N columns when inside a `columns` Form grid. */ colSpan?: number; className?: ClassNameProp; children?: never; /** Read-only value — renders as `Descriptions.Item`-matched text instead of a control. */ staticText: React.ReactNode; }; /** * @see FormErrors — the "no field to stand on" error summary. Renders the entries of the * surrounding `Form`'s error bag that no mounted `FormField name="…"` has claimed — validation * errors attached to hidden/derived fields (`action_mode`, `page`, a source-record id…) that * would otherwise fail silently. Renders nothing while every error is claimed or the bag is empty. */ export type FormErrorsProp = { /** * Explicit error bag — overrides the surrounding `Form errors`. Use it when the component sits * outside a `Form` (e.g. inside `FormRoot`); field claiming still applies when a `Form` provides * the registry. */ errors?: ErrorBagProp; /** Heading above the messages. Defaults to the localized "please review your input" title. */ title?: TitleProp; className?: ClassNameProp; }; /** * @see FormErrorsProvider — one shared error registry over a REGION of sibling Forms. An edit * screen split into several Card+Form sections shares a single server bag: wrap the sections in * this provider instead of passing `errors` to each Form, and every `FormField name="…"` inside * (Forms without their own `errors` join the surrounding registry) claims into the same registry, * so one `` anywhere in the region renders exactly the unclaimed remainder. * `Form errors={…}` renders this provider itself — a Form WITH its own `errors` starts a new * (shadowing) registry. */ export type FormErrorsProviderProp = { /** Server validation error bag shared by every Form/FormField in the region. */ errors?: ErrorBagProp; children?: React.ReactNode; }; /** @see SearchInput */ export type SearchInputProp = FieldA11yProps & { id?: IdProp; label?: LabelProp; ariaLabel?: string; placeholder?: PlaceholderProp; value?: string; defaultValue?: string; onValueChange?: (query: string) => void; /** Emits changed, debounced queries; does not run for the initial value. */ onSearch?: (query: string) => void; debounce?: number; disabled?: DisabledProp; className?: ClassNameProp; inputClassName?: ClassNameProp; /** Validation state the field paints — antd `status`. `error` also reports `aria-invalid`. */ status?: ControlStatusProp; /** Chrome level — antd `variant`. Default `outlined`. */ variant?: ControlVariantProp; }; /** * @see Checkbox * * Public shape unchanged from the @radix-ui/react-checkbox era — `checked` / `defaultChecked` take * the tri-state `"indeterminate"`, `onCheckedChange` reports it back, and `disabled` / `required` * keep their HTML spelling. checkbox.tsx translates all of it to react-aria's `isSelected` / * `isIndeterminate` / `onChange` / `isDisabled`; none of those names reach a consumer. Written out * here rather than derived from a primitive that the component no longer uses. */ export type CheckboxProp = Omit, "checked" | "defaultChecked" | "onChange"> & { checked?: boolean | "indeterminate"; defaultChecked?: boolean | "indeterminate"; onCheckedChange?: (checked: boolean | "indeterminate") => void; required?: boolean; /** * antd `indeterminate` — paint the PARTIAL mark (a dash) without changing `checked`. Radix * spells the same state as `checked="indeterminate"`; this is the antd spelling of it, and the * two compose: `indeterminate` wins while it is true, and the box falls back to `checked` after. */ indeterminate?: boolean; }; /** Shared option row — the conventional `CheckboxOptionType` shape. */ export type ChoiceOptionProp = { label: React.ReactNode; value: string; disabled?: boolean; description?: React.ReactNode; }; /** @see Checkbox.Group */ export type CheckboxGroupProp = FieldA11yProps & { value?: ValueProp; defaultValue?: DefaultValueProp; onValueChange?: OnValueChangeProp; options?: ChoiceOptionProp[]; orientation?: "horizontal" | "vertical"; disabled?: DisabledProp; name?: NameProp; /** Injected by FormField (or set directly) — applied to the `role="group"` container. */ id?: IdProp; className?: ClassNameProp; children?: React.ReactNode; }; /** @see Radio.Group */ export type RadioGroupProp = FieldA11yProps & { value?: ValueProp; defaultValue?: DefaultValueProp; onValueChange?: OnValueChangeProp; options?: ChoiceOptionProp[]; orientation?: "horizontal" | "vertical"; disabled?: DisabledProp; name?: NameProp; /** Injected by FormField (or set directly) — applied to the `role="radiogroup"` container. */ id?: IdProp; className?: ClassNameProp; children?: React.ReactNode; /** * antd `optionType` — how each choice is DRAWN. `default` is a radio dot beside its label; * `button` welds the choices into one segmented bar of radio buttons. The role stays * `radiogroup`/`radio` either way: this is paint, never semantics. */ optionType?: RadioOptionTypeProp; /** antd `buttonStyle` — fill of the selected choice while `optionType="button"`. */ buttonStyle?: RadioButtonStyleProp; }; /** antd `RadioGroupOptionType` — a radio group drawn as dots or as a welded button bar. */ export type RadioOptionTypeProp = "default" | "button"; /** antd `RadioGroupButtonStyle` — the selected button is outlined, or filled with the brand. */ export type RadioButtonStyleProp = "outline" | "solid"; /** * @see Radio.Item * * Public shape unchanged from the @radix-ui/react-radio-group era — `value` / `disabled` keep * their HTML spelling; react-aria's `isDisabled` never reaches a consumer. */ export type RadioProp = Omit, "value"> & { value: string; }; /** * @see Switch * * The PUBLIC shape is unchanged from the @radix-ui/react-switch era — `checked` / * `defaultChecked` / `onCheckedChange` / `disabled` / `required` keep their HTML spelling. * react-aria-components spells the same five `isSelected` / `defaultSelected` / `onChange` / * `isDisabled`, and that translation happens inside `switch.tsx`; none of those names reach a * consumer. Written out here rather than derived from a primitive so the surface stops moving * whenever the base does. */ export type SwitchProp = Omit, "checked" | "defaultChecked" | "onChange" | "value"> & { checked?: boolean; defaultChecked?: boolean; onCheckedChange?: (checked: boolean) => void; required?: boolean; size?: "sm" | "md"; /** * antd `loading` — the toggle is mid-flight: a spinner replaces the thumb glyph and the control * stops accepting input (`aria-disabled`, not `disabled`, so it keeps its tab stop and its * accessible name while a screen reader hears `aria-busy`). */ loading?: boolean; /** antd `checkedChildren` — content shown INSIDE the track while on (`ON`, `有効`, a glyph). */ checkedChildren?: React.ReactNode; /** antd `unCheckedChildren` — content shown inside the track while off. */ unCheckedChildren?: React.ReactNode; }; /** @see Field — inline control + label + description wrapper. */ export type FieldProp = { id: IdProp; label: LabelProp; /** * Optional content rendered BESIDE the label and OUTSIDE the `