# Components: Form layout

> Plainkit 0.28.0. Generated by scripts/build-skills.mjs from Generated/*.razor, blazor/mappings, generated.manifest.json and core/dist/elements/api.json. Do not edit: change the source and run the generator.

Every component renders its element with the parameters you set as attributes. An attribute that is not a parameter (`id`, `class`, `data-*`, `aria-*`, ...) is put on the element as it is, and a `class` is added to the component's own (`ExtraClass` on a component that lists it). Names are `Pk` plus the tag in PascalCase.

## `PkField`

`<pk-field>`: **Field** (Form layout). The label, help, error, warning and counter around a form control, with the wiring between them. It hands its label and messages to the control, because ids do not cross shadow roots.

**Parameters**

| Parameter | Type | Enum values | Sets | Description |
|---|---|---|---|---|
| `Label` | `string?` |  | attribute `label` | The label text (or use the label slot). |
| `Hint` | `string?` |  | attribute `help` | Help text under the control. |
| `Error` | `string?` |  | attribute `error` | An error message; puts the control into the invalid state. |
| `Required` | `bool` |  | attribute `required` | Marks the field required (a star, and required on the control). |
| `MaxLength` | `int` |  | attribute `max` | Counter maximum: shows length / max and turns warm from 90% and red past the max; 0 hides the counter. |
| `Layout` | `FieldLayout?` | `Stack` `Row` `Inline` | attribute `layout` | stack puts the label above the control; row puts it in a fixed column beside it (stacks on a phone); inline puts label and control on one line at their natural width. |
| `LabelActionEnd` | `bool` |  | attribute `action-end` | Pins the LabelAction content to the end of the label row instead of directly after the label text. |
| `Warning` | `string?` |  | attribute `warning` | A warning message; puts the control into the warning state. |
| `ChildContent` | `RenderFragment?` |  | default slot | The control: an pk-* form control or a native input, select or textarea. |
| `LabelExtra` | `RenderFragment?` |  | slot `label` | A rich label (overrides the label prop). |
| `LabelAction` | `RenderFragment?` |  | slot `label-action` | A small action beside the label, such as a reset to source button (a pk-button size mini, variant ghost). Clicking it does not focus the control. |
| `HintContent` | `RenderFragment?` |  | slot `help` | Rich help text (overrides the help prop). |
| `Size` | `FieldSize?` | `Md` `Sm` | attribute `size` | sm is the compact field of a toolbar or filter row: smaller label, tighter gap. |

When you set a named fragment (`LabelExtra`, `LabelAction`, `HintContent`), write the body as an explicit `<ChildContent>` tag too: Razor does not allow an implicit body next to a named fragment.

Element details (parts, CSS custom properties, methods, accessibility): `pk-field` in the `plainkit-sdk` skill.

## `PkFieldGroup`

`<pk-field-group>`: **Field group** (Form layout). A form drawn from a list of field specs: each entry becomes a pk-field with the right control (pk-input of every scalar type, pk-textarea, pk-select, pk-checkbox, pk-switch, pk-range, pk-combobox). Set fields (label, kind, hint, required, constraints, options, when) and values ({ key: value }); a committed change updates values and raises pk-field-change. A field with when (data: { field, equals | in | not }) or a visible(spec, values) callback property is not rendered at all while it is hidden, so a hidden required field can never block a submit; its value stays in values. A spec can also carry declarative conditions over the live committed values as text: whenExpr (or when given as a string), disabledExpr, readonlyExpr and requiredExpr, plus labelWhenExpr and helpWhenExpr for a label or help that follows the values, for example "status == 'paid' && amount > 100" (see the fields prop for the grammar); they are evaluated in the browser, by a module that loads only when a spec declares one. A combobox field takes its options from the search({ key, query }) callback property when it is set (a promise of [{ value, label }], like pk-combobox's pk-combo-query): the combobox then does not filter them itself. With a commit({ key, value, values }) callback property set, a committed change is handed to the host first and pk-field-change is raised only when it accepts: the field shows a busy state (aria-busy on the control and a small spinner beside the label) while the promise is pending, the last edit of a field wins (a stale answer changes nothing), and a rejection or a returned string shows as that field's error message with the typed text kept. The controls live in this element's shadow tree. The element is form-associated: a surrounding form gets one FormData entry per shown field (a checkbox or switch only when checked; a hidden or disabled field none) and the first invalid field's message as its validity, anchored on that field, which is focused when a submit or reportValidity() fails; pk-form lists every problem. A form reset puts the values back to the ones last assigned.

**Parameters**

| Parameter | Type | Enum values | Sets | Description |
|---|---|---|---|---|
| `Columns` | `int?` |  | attribute `columns` | How many columns the fields flow into, up to as many as fit (a column is at least 16rem wide, so a narrow group and a phone show one); a field with span fills the row and one with columnSpan takes that many columns. |
| `Layout` | `FieldGroupLayout?` | `Grid` `Inline` | attribute `layout` | grid (the form-section grid: columns, span and cols apply) or inline: the fields sit in one wrapping row, bottom-aligned with the content of the end slot, for a short add-row. A field is 12rem wide (shrinking) unless it has cols (1 to 12), which sizes it as twelfths of the row exactly as in the grid (never under 5rem), so a short quantity stays short beside a wide picker. span, columnSpan and columns are ignored inline. Bottom alignment is of the whole field, so a hint under one field lifts its control: keep hints out of an add-row. |
| `EndContent` | `RenderFragment?` |  | slot `end` | Trailing content on the fields' row with layout="inline" (the Add and Cancel buttons of an add-row), bottom-aligned with the controls. |
| `Fields` | `IReadOnlyList<PkFieldSpec<TItem>>` |  |  | The fields to render, in order. |
| `Model` | `TItem` |  |  | The bound record; each field's Get reads it, each commit calls Set then ModelChanged. |
| `OnFieldAction` | `EventCallback<PkFieldActionEventArgs>` |  | event `pk-field-action` | The user pressed a field's suffixAction button: the field's key and the action's key. |
| `ModelChanged` | `EventCallback` |  | two-way pair of `Model` | Raised after a field commits (the model was updated through Set, or SetAsync succeeded). A handler on the parent re-renders it and this group: Get, When, Disabled and HelpWhen are read again. |

Two-way binding: `@bind-Model`.

**Event args**

| Event | Args class | Fields |
|---|---|---|
| `pk-field-action` | `PkFieldActionEventArgs` | Key: string?, Action: string? |
| `pk-field-change` | `PkFieldChangeEventArgs` | Key: string?, Value: JsonElement?, Values: JsonElement? |

Element details (parts, CSS custom properties, methods, accessibility): `pk-field-group` in the `plainkit-sdk` skill.

## `PkFieldRow`

`<pk-field-row>`: **Field row** (Form layout). A wrapping row of fields that share the width: each field grows from a 120px minimum, a wide field takes a row of its own.

**Parameters**

| Parameter | Type | Enum values | Sets | Description |
|---|---|---|---|---|
| `Align` | `FieldRowAlign?` | `Stretch` `End` `Center` | attribute `align` | Vertical alignment of the fields in the row. |
| `ChildContent` | `RenderFragment?` |  | default slot | The fields, checkboxes or switches. |

Element details (parts, CSS custom properties, methods, accessibility): `pk-field-row` in the `plainkit-sdk` skill.

## `PkForm`

`<pk-form>`: **Form validation** (Form layout). Wraps a form and shows the browser's constraint validation well: messages in each field, a summary with links, focus on the first problem, and live re-checking. A pk-field-group inside the form is looked through: its fields show their own messages, and each invalid field is listed in the summary and can be focused from it.

**Parameters**

| Parameter | Type | Enum values | Sets | Description |
|---|---|---|---|---|
| `Validate` | `FormValidate?` | `Blur` `Input` `Submit` | attribute `validate` | When to check: blur (after leaving a field, and on submit), input (while typing) or submit (only on submit). A field already showing an error re-checks as you type. |
| `ShowValid` | `bool` |  | attribute `show-valid` | Also shows the valid state on fields that hold a value. |
| `Summary` | `bool` |  | attribute `summary` | Shows a summary of the problems with links to the fields; each item starts with its field's name ("Code: Please fill out this field."). |
| `OnInvalid` | `EventCallback<PkInvalidEventArgs>` |  | event `pk-invalid` | A submit was stopped because these controls are invalid. count, messages and problems have one entry per problem; a form-associated group of fields (pk-field-group) is listed once in controls and once per invalid field in problems. |
| `OnValid` | `EventCallback` |  | event `pk-valid` | A submit passed validation. |
| `OnReset` | `EventCallback` |  | event `pk-reset` | The form was reset and every control has its initial value again. A reset raises no input or change event on the controls (as with native controls), so a host that mirrors their values reads them again here. Not raised when the reset was cancelled. |
| `ChildContent` | `RenderFragment?` |  | default slot | A form element. |
| `SummaryTitleContent` | `RenderFragment?` |  | slot `summary-title` | The summary heading. |

When you set a named fragment (`SummaryTitleContent`), write the body as an explicit `<ChildContent>` tag too: Razor does not allow an implicit body next to a named fragment.

**Event args**

| Event | Args class | Fields |
|---|---|---|
| `pk-invalid` | `PkInvalidEventArgs` | Count: double? |

Element details (parts, CSS custom properties, methods, accessibility): `pk-form` in the `plainkit-sdk` skill.

## `PkFormActions`

`<pk-form-actions>`: **Form actions** (Form layout). The bar of buttons under a form, aligned start, end or between, and sticky to the bottom of a long form.

**Parameters**

| Parameter | Type | Enum values | Sets | Description |
|---|---|---|---|---|
| `Sticky` | `bool` |  | attribute `sticky` | Sticks to the bottom of the scrolling area with a top edge, clearing the phone home indicator. |
| `Align` | `FormActionsAlign?` | `Start` `End` `Between` | attribute `align` | Where the buttons sit. |
| `ChildContent` | `RenderFragment?` |  | default slot | The buttons. |
| `StatusContent` | `RenderFragment?` |  | slot `status` | A status message such as "Unsaved changes". |

When you set a named fragment (`StatusContent`), write the body as an explicit `<ChildContent>` tag too: Razor does not allow an implicit body next to a named fragment.

Element details (parts, CSS custom properties, methods, accessibility): `pk-form-actions` in the `plainkit-sdk` skill.

## `PkFormSection`

`<pk-form-section>`: **Form section** (Form layout). A titled section of a form: heading and description beside a responsive grid of fields (stacked at 1024px and below).

**Parameters**

| Parameter | Type | Enum values | Sets | Description |
|---|---|---|---|---|
| `Title` | `string?` |  | attribute `heading` | The section heading (or use the heading slot). |
| `Description` | `string?` |  | attribute `description` | A sentence under the heading. |
| `ChildContent` | `RenderFragment?` |  | default slot | The fields. Give a child class form-span to make it span the full width. |
| `HeadingContent` | `RenderFragment?` |  | slot `heading` | A rich heading. |
| `DescriptionContent` | `RenderFragment?` |  | slot `description` | A rich description. |

When you set a named fragment (`HeadingContent`, `DescriptionContent`), write the body as an explicit `<ChildContent>` tag too: Razor does not allow an implicit body next to a named fragment.

Element details (parts, CSS custom properties, methods, accessibility): `pk-form-section` in the `plainkit-sdk` skill.

## `PkRecordForm`

`<pk-record-form>`: **Record form** (Form layout). The page layout of a create-or-edit record around your own form: a toolbar (Cancel, your actions, Delete, Save), optional tabs, an error alert, the form in a pk-form (a summary of the problems, focus on the first, live checks), and an optional sidebar of status cards beside it (pk-detail-layout, one column on a phone). It owns no values, no load and no save: put your own <form> (and its fields) in the default slot, listen for pk-record-save when it validates, and keep the state yourself. Save submits your form, so pk-form checks it first. With actions-in-header the toolbar row is left out and a Save button in the page header calls submit() instead. On a phone the toolbar buttons fold to their icons (the words stay their names).

**Parameters**

| Parameter | Type | Enum values | Sets | Description |
|---|---|---|---|---|
| `SaveLabel` | `string?` |  | attribute `save-label` | The Save button's text. Change it only for a page whose submit is an action ("Record payout"). |
| `DeleteLabel` | `string?` |  | attribute `delete-label` | The Delete button's text. |
| `BusyText` | `string?` |  | attribute `busy-text` | The Save button's text while busy. |
| `SaveDisabled` | `bool` |  | attribute `save-disabled` | Disables Save (a locked record, or nothing to save yet). Independent of busy. |
| `Busy` | `bool` |  | attribute `busy` | Save shows its busy state and Delete is disabled while the page saves or deletes. |
| `Error` | `string?` |  | attribute `error` | A message shown in an error alert above the form; empty shows none. |
| `TabsFrom` | `RecordFormTabsFrom?` | `Phone` `Tablet` `Always` | attribute `tabs-from` | Where the tabs in the tabs slot take effect. An element in the form or the sidebar with a tab attribute (a tab value, or several separated by spaces) belongs to those tabs: at or below the width named (phone, tablet), or always, only the chosen tab's sections show and the strip is visible; above it every section shows (the two-column layout) and the strip is hidden. Sections with no tab attribute always show. The element sets hidden on the tagged sections. |
| `TabParam` | `string?` |  | attribute `tab-param` | A query parameter name ("tab") that keeps the chosen tab in the address bar, so a reload or a shared link opens on it. Other parameters and the hash are kept and no history entry is added. Empty keeps nothing. A value that matches no enabled tab is ignored. |
| `TabItems` | `IReadOnlyList<PkRecordTab>?` |  | attribute `tabs` | The tabs as data: an array of { value, label, count?, visible? }. The element draws the strip (a pk-tabs in the tabs slot wins); count is the badge after the label, and a tab with visible false is left out (a chosen tab that went falls back to the first). Sections tag themselves with tab="value" as with tabs-from. Empty draws nothing. |
| `ActionsInHeader` | `bool` |  | attribute `actions-in-header` | Leaves the toolbar row out so the buttons can sit in the page's own header and stay visible in its sticky title bar. Put your own Save button in the header and have it call submit() (a form attribute cannot cross this element's shadow root). |
| `OnValid` | `EventCallback` |  | event `pk-record-save` | Save was pressed (or submit() called, or the form submitted) and pk-form found the form valid: save the record. An invalid form raises no event; pk-form shows the problems. |
| `OnCancel` | `EventCallback` |  | event `pk-record-cancel` | Cancel was pressed. |
| `OnDelete` | `EventCallback` |  | event `pk-record-delete` | Delete was pressed. |
| `ChildContent` | `RenderFragment?` |  | default slot | Your own form element, with its fields. pk-form wraps it. |
| `Sidebar` | `RenderFragment?` |  | slot `sidebar` | Status and flag cards beside the form (pk-detail-layout). Left empty, the form takes the whole width. |
| `Actions` | `RenderFragment?` |  | slot `actions` | Extra toolbar buttons, between Cancel and Delete. |
| `Tabs` | `RenderFragment?` |  | slot `tabs` | A pk-tabs strip for a record with more than one job, under the toolbar. Tag sections with a tab attribute (see tabs-from) and the chosen tab shows its sections, or render the chosen tab's content yourself. |

When you set a named fragment (`Sidebar`, `Actions`, `Tabs`), write the body as an explicit `<ChildContent>` tag too: Razor does not allow an implicit body next to a named fragment.

Element details (parts, CSS custom properties, methods, accessibility): `pk-record-form` in the `plainkit-sdk` skill.
