# Components: Form controls

> 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.

## `PkCalendar`

`<pk-calendar>`: **Calendar** (Forms). A small month grid to pick or show a date, with marks, minimum and maximum, and full keyboard control.

**Parameters**

| Parameter | Type | Enum values | Sets | Description |
|---|---|---|---|---|
| `Value` | `DateOnly?` |  | attribute `value` | The selected day, an ISO date such as 2026-09-19. |
| `ValueChanged` | `EventCallback<DateOnly?>` |  | two-way pair of `Value` | Raised with the new value of Value (two-way: Value follows it). |
| `Month` | `DateOnly?` |  | attribute `month` | An ISO date whose month is shown; defaults to the value or today. |
| `MonthChanged` | `EventCallback<DateOnly?>` |  | two-way pair of `Month` | Raised when Month changes (two-way binding: `@bind-Month`). |
| `Min` | `DateOnly?` |  | attribute `min` | Earliest selectable ISO date. |
| `Max` | `DateOnly?` |  | attribute `max` | Latest selectable ISO date. |
| `WeekStart` | `int` |  | attribute `week-start` | First weekday: 0 Sunday, 1 Monday. |
| `Locale` | `string?` |  | attribute `locale` | Language of month and weekday names; defaults to the page language. |
| `Marks` | `IReadOnlyList<DateOnly>?` |  | attribute `marks` | ISO dates that get a dot. |
| `Range` | `bool` |  | attribute `range` | Pick a range of days instead of one: the first click sets the start, the second the end (swapped when earlier), the days between are highlighted and a pending range previews under the pointer or focus. Escape drops a pending start. |
| `Start` | `DateOnly?` |  | attribute `start` | Range mode: the first day of the range, an ISO date such as 2026-09-01. |
| `StartChanged` | `EventCallback<DateOnly?>` |  | two-way pair of `Start` | Raised when Start changes (two-way binding: `@bind-Start`). |
| `End` | `DateOnly?` |  | attribute `end` | Range mode: the last day of the range, an ISO date such as 2026-09-14. |
| `EndChanged` | `EventCallback<DateOnly?>` |  | two-way pair of `End` | Raised when End changes (two-way binding: `@bind-End`). |
| `ReadOnly` | `bool` |  | attribute `readonly` | Show only; no selection. |
| `Disabled` | `bool` |  | attribute `disabled` | Inert. |
| `OnRangeChange` | `EventCallback<PkRangeChangeEventArgs>` |  | event `pk-range-change` | Range mode: the second click set the end and the range is complete. The same detail as pk-date-range-picker; valid is always true here because min and max cannot be picked past. |
| `OnMonthChanged` | `EventCallback<PkMonthEventArgs>` |  | event `pk-month` | The shown month changed (yyyy-mm). |

Two-way binding: `@bind-Value`, `@bind-Month`, `@bind-Start`, `@bind-End`.

**Event args**

| Event | Args class | Fields |
|---|---|---|
| `pk-month` | `PkMonthEventArgs` | Month: string? |
| `pk-range-change` | `PkRangeChangeEventArgs` | Start: string?, End: string?, Valid: bool?, Preset: string? |
| `pk-select` | `PkSelectEventArgs` | Item: JsonElement?, Value: string?, Checked: bool?, Id: string?, Selected: string[]?, Scope: string?, Query: JsonElement? |

Element details (parts, CSS custom properties, methods, accessibility): `pk-calendar` in the `plainkit-sdk` skill.

## `PkCheckbox`

`<pk-checkbox>`: **Checkbox** (Form controls). A checkbox drawn from tokens, with an indeterminate state and select-all groups: a master checkbox mirrors every checkbox of its group.

**Parameters**

| Parameter | Type | Enum values | Sets | Description |
|---|---|---|---|---|
| `Checked` | `bool` |  | attribute `checked` | Whether the box is checked. A form reset sets it back to its initial value without raising the commit event, as a native control does: pk-form raises pk-reset after it, so a host that mirrors the value reads it again there. A browser state restore also sets it silently. |
| `Name` | `string?` |  | attribute `name` | The form field name. |
| `Disabled` | `bool` |  | attribute `disabled` | Blocks interaction; also set by a disabled fieldset. |
| `Required` | `bool` |  | attribute `required` | The form cannot be submitted while the value is empty. |
| `IsInvalid` | `bool` |  | attribute `invalid` | Shows the invalid state and sets aria-invalid; set by pk-field or pk-form (or by a Blazor EditContext). |
| `Indeterminate` | `bool` |  | attribute `indeterminate` | The mixed state (some of a group are checked). |
| `Group` | `string?` |  | attribute `group` | Puts this checkbox in a select-all group of that name. |
| `Master` | `string?` |  | attribute `master` | Makes this the select-all checkbox of the group of that name; it shows checked, unchecked or indeterminate as its members change. |
| `Label` | `string?` |  | attribute `label` | The accessible name (aria-label). pk-field fills it from its own label when this is empty. |
| `Description` | `string?` |  | attribute `description` | Help and error text, exposed as aria-description; pk-field fills it. |
| `OnInput` | `EventCallback<ChangeEventArgs>` |  | event `input` | The value changed (native, composed: bubbles out of the shadow root). Read event.target.value. |
| `OnChange` | `EventCallback<ChangeEventArgs>` |  | event `change` | The user committed the value (re-dispatched from the inner control, composed). |
| `ChildContent` | `RenderFragment?` |  | default slot | The label. |
| `Size` | `CheckboxSize?` | `Md` `Sm` | attribute `size` | sm is the compact checkbox of a toolbar: smaller label text. |
| `CheckedChanged` | `EventCallback<bool>` |  | two-way pair of `Checked` | Raised when Checked changes (two-way binding: `@bind-Checked`). |
| `CheckedExpression` | `Expression<Func<bool>>?` |  |  | The expression that names the bound field (`@bind-Checked` sets it); lets the control take part in an `EditForm`: validation state and modified tracking. |

Two-way binding: `@bind-Checked`.

**Event args**

| Event | Args class | Fields |
|---|---|---|
| `pk-change` | `PkChangeEventArgs` | Checked: bool?, Index: double?, Value: string?, Label: string?, Previous: string? |

Element details (parts, CSS custom properties, methods, accessibility): `pk-checkbox` in the `plainkit-sdk` skill.

## `PkColourInput`

`<pk-colour-input>`: **Colour input** (Form controls). The native colour picker beside an editable hex field that stay in step; the field accepts #abc, abc and #aabbcc and is normalised to #rrggbb.

**Parameters**

| Parameter | Type | Enum values | Sets | Description |
|---|---|---|---|---|
| `Value` | `string?` |  | attribute `value` | The colour as #rrggbb. A form reset sets it back to its initial value without raising the commit event, as a native control does: pk-form raises pk-reset after it, so a host that mirrors the value reads it again there. A browser state restore also sets it silently. |
| `Disabled` | `bool` |  | attribute `disabled` | Blocks interaction; also set by a disabled fieldset. |
| `Required` | `bool` |  | attribute `required` | The form cannot be submitted while the value is empty. |
| `IsInvalid` | `bool` |  | attribute `invalid` | Shows the invalid state and sets aria-invalid; set by pk-field or pk-form (or by a Blazor EditContext). |
| `ShowLabel` | `bool` |  | attribute `show-label` | Shows label as visible text above the field (linked to it), for use without a pk-field. |
| `AriaLabel` | `string?` |  | attribute `label` | The accessible name (aria-label). pk-field fills it from its own label when this is empty. |
| `Name` | `string?` |  | attribute `name` | The form field name. |
| `Description` | `string?` |  | attribute `description` | Help and error text, exposed as aria-description; pk-field fills it. |
| `OnInput` | `EventCallback<ChangeEventArgs>` |  | event `input` | The value changed (native, composed: bubbles out of the shadow root). Read event.target.value. |
| `OnChange` | `EventCallback<ChangeEventArgs>` |  | event `change` | The user committed the value (re-dispatched from the inner control, composed). |
| `ValueChanged` | `EventCallback<string?>` |  | two-way pair of `Value` | Raised when Value changes (two-way binding: `@bind-Value`). |
| `ValueExpression` | `Expression<Func<string?>>?` |  |  | The expression that names the bound field (`@bind-Value` sets it); lets the control take part in an `EditForm`: validation state and modified tracking. |

Two-way binding: `@bind-Value`.

**Event args**

| Event | Args class | Fields |
|---|---|---|
| `pk-colour` | `PkColourEventArgs` | Value: string? |

Element details (parts, CSS custom properties, methods, accessibility): `pk-colour-input` in the `plainkit-sdk` skill.

## `PkCombobox`

`<pk-combobox>`: **Combobox** (Form controls). An autocomplete (type to filter a list) or, with mode="select", a custom select. ARIA combobox with the highlight tracked by aria-activedescendant, so focus stays on the control. Its options are its own option children. For a server search set the search(query, { signal }) property: it returns a promise of [{ value, label }] that becomes the list (client filter off); a newer query aborts the signal and late answers are dropped.

**Parameters**

| Parameter | Type | Enum values | Sets | Description |
|---|---|---|---|---|
| `Value` | `string?` |  | attribute `value` | The current value; what the form submits. A form reset sets it back to its initial value without raising the commit event, as a native control does: pk-form raises pk-reset after it, so a host that mirrors the value reads it again there. A browser state restore also sets it silently. |
| `Placeholder` | `string?` |  | attribute `placeholder` | Hint shown while empty. |
| `Disabled` | `bool` |  | attribute `disabled` | Blocks interaction; also set by a disabled fieldset. |
| `Required` | `bool` |  | attribute `required` | The form cannot be submitted while the value is empty. |
| `IsInvalid` | `bool` |  | attribute `invalid` | Shows the invalid state and sets aria-invalid; set by pk-field or pk-form (or by a Blazor EditContext). |
| `Mode` | `ComboboxMode?` | `Autocomplete` `Select` | attribute `mode` | autocomplete filters as you type; select is a button that opens the list (type a letter to jump). Prefer the native pk-select on a phone. |
| `Free` | `bool` |  | attribute `free` | Autocomplete: keep typed text that is not an option, and use it as the value. |
| `Clearable` | `bool` |  | attribute `clearable` | Autocomplete: shows a clear button while a value is chosen. It sets the value to empty, raises change and pk-combo-select (value "", label ""), and puts focus back on the input. For an optional picked value. |
| `Filtering` | `ComboboxFiltering?` | `Client` `Off` | attribute `filtering` | client also filters the options here; off leaves filtering to the host, which listens for pk-combo-query and replaces the options (or sets the search callback, which turns the client filter off by itself). |
| `DebounceMs` | `int` |  | attribute `debounce` | Milliseconds to wait after typing before pk-combo-query fires, with the latest text only; 0 fires on every keystroke. The client filter is not delayed. For a host that fetches options from the query. |
| `Open` | `bool` |  | attribute `open` | Whether the list is open. |
| `OpenChanged` | `EventCallback<bool>` |  | two-way pair of `Open` | Raised when Open changes (two-way binding: `@bind-Open`). |
| `AriaLabel` | `string?` |  | attribute `label` | The accessible name (aria-label). pk-field fills it from its own label when this is empty. |
| `Name` | `string?` |  | attribute `name` | The form field name. |
| `Description` | `string?` |  | attribute `description` | Help and error text, exposed as aria-description; pk-field fills it. |
| `OnSearchInput` | `EventCallback<PkComboQueryEventArgs>` |  | event `pk-combo-query` | The user typed: the text so far, so a host can fetch more options (with filtering="off" it also replaces the client filter). |
| `OnSearch` | `Func<string, CancellationToken, Task<IReadOnlyList<PkFieldOption>>>?` |  |  | Answers the typed text with the options to list (the answer replaces the list, and the built-in filter is off while it is set). A query a newer one replaces, or the component going away, cancels its CancellationToken and the late answer is dropped by the element. Use it instead of OnSearchInput plus re-rendering the options when the search should be cancellable. |
| `OnInput` | `EventCallback<ChangeEventArgs>` |  | event `input` | The value changed (native, composed: bubbles out of the shadow root). Read event.target.value. |
| `OnChange` | `EventCallback<ChangeEventArgs>` |  | event `change` | The user committed the value (re-dispatched from the inner control, composed). |
| `ChildContent` | `RenderFragment?` |  | default slot | option elements (value, disabled and text). |
| `EmptyContent` | `RenderFragment?` |  | slot `empty` | The message shown when nothing matches. |
| `OnToggle` | `EventCallback<PkComboToggleEventArgs>` |  | event `pk-combo-toggle` | The list opened or closed by itself (typing, a click, a key, focus leaving); open already has the new value. Not raised for a change the host made. |
| `ValueChanged` | `EventCallback<string?>` |  | two-way pair of `Value` | Raised when Value changes (two-way binding: `@bind-Value`). |
| `ValueExpression` | `Expression<Func<string?>>?` |  |  | The expression that names the bound field (`@bind-Value` sets it); lets the control take part in an `EditForm`: validation state and modified tracking. |

Two-way binding: `@bind-Open`, `@bind-Value`.

When you set a named fragment (`EmptyContent`), 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-combo-query` | `PkComboQueryEventArgs` | Query: string? |
| `pk-combo-select` | `PkComboSelectEventArgs` | Value: string?, Label: string? |
| `pk-combo-toggle` | `PkComboToggleEventArgs` | Open: bool? |

Element details (parts, CSS custom properties, methods, accessibility): `pk-combobox` in the `plainkit-sdk` skill.

## `PkDateRangePicker`

`<pk-date-range-picker>`: **Date range picker** (Form controls). A start and an end date with quick ranges (last 7 days, this month), a minimum and maximum, and an inline error when the end is before the start. Built on native date fields, so keyboard, touch and the platform picker come with it.

**Parameters**

| Parameter | Type | Enum values | Sets | Description |
|---|---|---|---|---|
| `Start` | `DateOnly?` |  | attribute `start` | The first day, an ISO date such as 2026-09-01. A form reset sets it back to its initial value without raising the commit event, as a native control does: pk-form raises pk-reset after it. A browser state restore also sets it silently. |
| `Name` | `string?` |  | attribute `name` | The form field name. The submitted value is the ISO interval start/end, for example 2026-09-01/2026-09-07, or empty when neither date is set. |
| `Description` | `string?` |  | attribute `description` | Help and error text, exposed as aria-description; pk-field fills it. |
| `Required` | `bool` |  | attribute `required` | The form cannot be submitted until both dates are set. |
| `StartChanged` | `EventCallback<DateOnly?>` |  | two-way pair of `Start` | Raised with the new value of Start (two-way: Start follows it). |
| `End` | `DateOnly?` |  | attribute `end` | The last day, an ISO date (inclusive). Same reset and restore behaviour as start. |
| `EndChanged` | `EventCallback<DateOnly?>` |  | two-way pair of `End` | Raised when End changes (two-way binding: `@bind-End`). |
| `Min` | `DateOnly?` |  | attribute `min` | Earliest allowed ISO date. A date before it makes the field invalid and disables a quick range that lies wholly before it. |
| `Max` | `DateOnly?` |  | attribute `max` | Latest allowed ISO date. |
| `Presets` | `string?` |  | attribute `presets` | The quick ranges to offer, comma separated, in order: today, 7d, 30d, 90d, month, lastmonth, quarter, lastquarter, year, lastyear, thismonth, thisquarter, thisyear (the whole period, to its last day). Empty for none. A range is cut to min and max. Keys of presetItems may be named here to place them; the ones not named follow. Built-in tokens: today, 7d, 30d, 90d, month, lastmonth, quarter, lastquarter, year, lastyear, thismonth, thisquarter, thisyear (the whole period, to its last day). |
| `PresetItems` | `IReadOnlyList<PkDatePreset>?` |  | attribute `preset-items` | Your own named quick ranges (Key, Label, Start, End), shown after the Presets tokens; OnRangeChange reports the Key of the one the range equals as Preset. |
| `StartLabel` | `string?` |  | attribute `start-label` | The accessible name of the start field; "Start date" when empty. Set it to localise. |
| `EndLabel` | `string?` |  | attribute `end-label` | The accessible name of the end field; "End date" when empty. |
| `Calendar` | `bool` |  | attribute `calendar` | Adds a calendar button after the end field that opens a pk-calendar in range mode in a pk-popover. The first click sets the start, the second the end and closes it; the fields stay, so the calendar is an addition and the native inputs are the fallback. Focus moves into the calendar on open, and Escape closes it and returns focus to the button. |
| `Disabled` | `bool` |  | attribute `disabled` | Blocks interaction; also set by a disabled fieldset. |
| `ReadOnly` | `bool` |  | attribute `readonly` | Shows the range without letting the user change it. |
| `IsInvalid` | `bool` |  | attribute `invalid` | Shows the invalid state and sets aria-invalid; set by pk-field or pk-form (or by a Blazor EditContext). The element also shows its own error when the end is before the start or a date is outside min and max. |
| `AriaLabel` | `string?` |  | attribute `label` | The accessible name of the group (aria-label). pk-field fills it from its own label when this is empty. |
| `OnRangeChange` | `EventCallback<PkRangeChangeEventArgs>` |  | event `pk-range-change` | The range changed by the user (a date typed or picked, a quick range, clear). valid is false when the end is before the start or a date is outside min and max; the values are still reported so the host can show its own message. preset is the key of the quick range the range equals (built in or from presetItems), else empty. |
| `OnInput` | `EventCallback<ChangeEventArgs>` |  | event `input` | A field changed while the user typed (native, composed: bubbles out of the shadow root). Read event.target.start and event.target.end. |
| `OnChange` | `EventCallback<ChangeEventArgs>` |  | event `change` | The user committed a date or a quick range (re-dispatched from the inner control, composed). |

Two-way binding: `@bind-Start`, `@bind-End`.

**Event args**

| Event | Args class | Fields |
|---|---|---|
| `pk-range-change` | `PkRangeChangeEventArgs` | Start: string?, End: string?, Valid: bool?, Preset: string? |

Element details (parts, CSS custom properties, methods, accessibility): `pk-date-range-picker` in the `plainkit-sdk` skill.

## `PkDropzone`

`<pk-dropzone>`: **Dropzone** (Form controls). A drop target over a real file input: drag files in or click, with type, size and count checks, a list of accepted files with Remove, and a reason for each rejection. Files are submitted with the form.

**Parameters**

| Parameter | Type | Enum values | Sets | Description |
|---|---|---|---|---|
| `Accept` | `string?` |  | attribute `accept` | Accepted types: extensions, MIME types or type/* (like the accept attribute). |
| `Multiple` | `bool` |  | attribute `multiple` | Allows several files. |
| `MaxFileSizeBytes` | `string?` |  | attribute `max-size` | Largest file: 500KB, 5MB, 1GB or bytes. |
| `MaxFiles` | `int` |  | attribute `max-files` | Most files (multiple); 0 means no limit. |
| `Label` | `string?` |  | attribute `label` | The accessible name (aria-label). pk-field fills it from its own label when this is empty. |
| `BrowseLabel` | `string?` |  | attribute `browse-label` | Shows a real button with this text inside the zone (for example "Choose files") that opens the file picker. It becomes the zone's keyboard stop, and the file input stays only as the click target. Empty (the default) draws no button: the whole zone opens the picker. |
| `Disabled` | `bool` |  | attribute `disabled` | Blocks interaction; also set by a disabled fieldset. |
| `Name` | `string?` |  | attribute `name` | The form field name. |
| `Description` | `string?` |  | attribute `description` | Help and error text, exposed as aria-description; pk-field fills it. |
| `Required` | `bool` |  | attribute `required` | The form cannot be submitted while the value is empty. |
| `IsInvalid` | `bool` |  | attribute `invalid` | Shows the invalid state and sets aria-invalid; set by pk-field or pk-form (or by a Blazor EditContext). |
| `OnFiles` | `EventCallback<PkFilesEventArgs>` |  | event `pk-files` | Files were picked or dropped: those kept and those refused with a reason. |
| `OnChange` | `EventCallback<ChangeEventArgs>` |  | event `change` | The file list changed. |
| `ChildContent` | `RenderFragment?` |  | default slot | The zone title. |
| `HintContent` | `RenderFragment?` |  | slot `hint` | A hint under the title (types and limits). |

When you set a named fragment (`HintContent`), 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-files` | `PkFilesEventArgs` | Count: double?, RejectedCount: double? |

Element details (parts, CSS custom properties, methods, accessibility): `pk-dropzone` in the `plainkit-sdk` skill.

## `PkInput`

`<pk-input>`: **Input** (Form controls). The single-line control: text, email, url, tel, search, password, number and the date and time types, with an optional clear button, password reveal, number stepper, money format, prefix and suffix, and a floating label.

**Parameters**

| Parameter | Type | Enum values | Sets | Description |
|---|---|---|---|---|
| `Value` | `string?` |  | attribute `value` | The current value; what the form submits. A form reset or browser restore sets it silently, as a native control does (pk-form raises pk-reset after a reset). |
| `Type` | `InputType?` | `Text` `Email` `Url` `Tel` `Search` `Password` `Number` `Date` `Time` `DatetimeLocal` `Month` `Week` | attribute `type` | The kind of value. Date and time types open the platform picker. |
| `Name` | `string?` |  | attribute `name` | The form field name. |
| `Placeholder` | `string?` |  | attribute `placeholder` | Hint shown while empty (ignored by a floating label). |
| `AriaLabel` | `string?` |  | attribute `label` | The accessible name (aria-label). pk-field fills it from its own label when this is empty. |
| `Disabled` | `bool` |  | attribute `disabled` | Blocks interaction; also set by a disabled fieldset. |
| `ReadOnly` | `bool` |  | attribute `readonly` | The value can be read and selected but not edited. |
| `Required` | `bool` |  | attribute `required` | The form cannot be submitted while the value is empty. |
| `IsInvalid` | `bool` |  | attribute `invalid` | Shows the invalid state and sets aria-invalid; set by pk-field or pk-form (or by a Blazor EditContext). |
| `Min` | `string?` |  | attribute `min` | Minimum value (number and date types). |
| `Max` | `string?` |  | attribute `max` | Maximum value (number and date types). |
| `Step` | `string?` |  | attribute `step` | Step for number and date types; also the stepper increment. |
| `MaxLength` | `string?` |  | attribute `maxlength` | Maximum text length. |
| `Pattern` | `string?` |  | attribute `pattern` | A regular expression the whole value must match. |
| `AutoComplete` | `string?` |  | attribute `autocomplete` | The autofill token, for example current-password, new-password or one-time-code. |
| `Font` | `string?` |  | attribute `font` | Font family of the text: sans or mono (for code, queries, ids). Default inherit. |
| `Width` | `string?` |  | attribute `width` | Width: xs to 2xl, or a CSS length. |
| `Size` | `InputSize?` | `Sm` `Md` `Lg` | attribute `size` | Control height. |
| `Clearable` | `bool` |  | attribute `clearable` | Shows a clear button while there is a value. |
| `Revealable` | `bool` |  | attribute `reveal` | Password only: a show and hide button. |
| `Copyable` | `bool` |  | attribute `copyable` | Shows a copy-to-clipboard button next to the value; disabled while empty and gives brief "Copied" feedback. Fails silently (logged, not shown) on an insecure origin or a denied permission. |
| `Stepper` | `bool` |  | attribute `stepper` | Number only: minus and plus buttons that respect min, max and step. |
| `Format` | `InputFormat?` | `None` `Money` | attribute `format` | money formats the value as an amount (1,234.50) when the field is left and shows the plain number while editing; value stays the plain number. |
| `Currency` | `string?` |  | attribute `currency` | ISO currency code whose symbol leads a money field. |
| `Floating` | `bool` |  | attribute `floating` | Shows label inside the field until it has focus or a value, then floats it to the top edge. |
| `ShowLabel` | `bool` |  | attribute `show-label` | Shows label as visible text above the field (linked to it), for use without a pk-field. Ignored by a floating label. |
| `DebounceMs` | `int` |  | attribute `debounce` | Search only: milliseconds to wait after typing before pk-search fires; 0 fires on every change. |
| `SearchOn` | `InputSearchOn?` | `Change` `Enter` | attribute `search-on` | Search only: when pk-search fires. change: while typing (after debounce) and at once on Enter, clear and when the box becomes empty. enter: only on Enter and clear (the clear button, the browser's own clear button, Escape, or deleting every character), never while typing, for a lookup or barcode box. |
| `Description` | `string?` |  | attribute `description` | Help and error text, exposed as aria-description; pk-field fills it. |
| `Warning` | `bool` |  | attribute `warning` | Shows the warning state (a value the user may want to check). |
| `IsValid` | `bool` |  | attribute `valid` | Shows the valid state. |
| `MinLength` | `string?` |  | attribute `minlength` | Minimum text length. |
| `InputMode` | `string?` |  | attribute `inputmode` | The virtual keyboard to request (numeric, decimal, email, ...). |
| `Decimals` | `int` |  | attribute `decimals` | Decimal places for the money format. |
| `Locale` | `string?` |  | attribute `locale` | Locale for money formatting. |
| `SelectOnFocus` | `bool` |  | attribute `select-on-focus` | Selects the whole value when the control gains focus (keyboard, tap or click), so typing replaces it. Useful for number inputs on a phone. |
| `AutoHide` | `int` |  | attribute `autohide` | Password reveal: seconds until the value is masked again; 0 keeps it revealed. |
| `Listbox` | `string?` |  |  | The id of the listbox element this input drives, making it a combobox (aria-controls, and the option marked aria-selected as the active descendant). Resolved in the input's own tree after each render in which the id changed. |
| `OnSearch` | `EventCallback<PkSearchEventArgs>` |  | event `pk-search` | Search type: the search text in detail.value (Blazor PkSearchEventArgs.Value; Query is pk-table-filters' field), debounced while typing, at once on Enter and clear; with search-on="enter" only on Enter and clear. Raised with the search text in Value (Query stays null: it is pk-table-filters' field). With SearchOn Enter only on Enter and clear (either clear button, Escape, or an emptied box), with an empty Value for a clear. |
| `OnInput` | `EventCallback<ChangeEventArgs>` |  | event `input` | The value changed (native, composed: bubbles out of the shadow root). Read event.target.value. |
| `OnChange` | `EventCallback<ChangeEventArgs>` |  | event `change` | The user committed the value (re-dispatched from the inner control, composed). |
| `PrefixContent` | `RenderFragment?` |  | slot `prefix` | A leading add-on: a currency sign, an icon, a unit. |
| `SuffixContent` | `RenderFragment?` |  | slot `suffix` | A trailing add-on: a unit, a domain, a button. |
| `ValueChanged` | `EventCallback<string?>` |  | two-way pair of `Value` | Raised when Value changes (two-way binding: `@bind-Value`). |
| `ValueExpression` | `Expression<Func<string?>>?` |  |  | The expression that names the bound field (`@bind-Value` sets it); lets the control take part in an `EditForm`: validation state and modified tracking. |

Two-way binding: `@bind-Value`.

**Event args**

| Event | Args class | Fields |
|---|---|---|
| `pk-search` | `PkSearchEventArgs` | Value: string?, Query: string? |
| `pk-value-change` | `PkValueChangeEventArgs` | Value: string?, Values: string[]? |

Element details (parts, CSS custom properties, methods, accessibility): `pk-input` in the `plainkit-sdk` skill.

## `PkLookupPicker`

`<pk-lookup-picker>`: **Lookup picker** (Form controls). A select-style field for a long list (customers, products, users) that does not fit pk-combobox: its popup holds a searchable, pageable pk-data-table, so the reader tells rows apart by columns. Set the load(query) callback as a property, exactly as pk-data-table's: it receives { page, pageSize, sort, sortDir, search, filters } and { signal }, and returns (or resolves to) { rows, total }; loading, error and empty states come from the table. Picking a row sets value to its rowKey field and closes the popup. The field shows the option's label: its labelKey field when picked in this session, else selectedLabels[value], else what the resolve(keys) callback property returns for it ({ key: label } or [{ key, label }]), so a stored value shows its name even when its row is on no loaded page. The popup is built on the first open: a closed picker loads nothing but itself.

**Parameters**

| Parameter | Type | Enum values | Sets | Description |
|---|---|---|---|---|
| `Value` | `string?` |  | attribute `value` | The key (rowKey field) of the chosen row; what the form submits. A form reset sets it back to its initial value silently, as a native control does. The key of the chosen item when not Multiple (two-way: @bind-Value; ValueExpression for an EditForm). |
| `Values` | `IReadOnlyList<string>?` |  | attribute `values` | The keys of the chosen rows when multiple is set, as an array of strings (any text, commas included); what the form submits. A form reset sets it back to its initial value silently. Chip labels come from the rows seen, selectedLabels or resolve(keys), which is asked once for all keys with no label. The keys of the chosen items when Multiple (two-way: @bind-Values; ValuesExpression for an EditForm). |
| `ValuesChanged` | `EventCallback<IReadOnlyList<string>?>` |  | two-way pair of `Values` | Raised when Values changes (two-way binding: `@bind-Values`). |
| `Name` | `string?` |  | attribute `name` | The form field name. |
| `Multiple` | `bool` |  | attribute `multiple` | Several rows can be chosen: the popup table gets a checkbox column (the selection survives paging and searching; there is no select-all across pages) and stays open while ticking; the chosen rows show as removable chips under the field. The form submits one entry per key under name. |
| `Max` | `int` |  | attribute `max` | The most rows a multiple picker accepts (0: no limit). A tick past it is undone and announced. |
| `SelectedLabels` | `IReadOnlyDictionary<string, string>?` |  | attribute `selected-labels` | { key: label } for values whose row is not on a loaded page, so the field can show a stored value's name without asking the server. |
| `Placeholder` | `string?` |  | attribute `placeholder` | Hint shown while empty. |
| `Disabled` | `bool` |  | attribute `disabled` | Blocks interaction; also set by a disabled fieldset. |
| `Readonly` | `bool` |  | attribute `readonly` | Shows the value but cannot open the popup. |
| `Required` | `bool` |  | attribute `required` | The form cannot be submitted while no row is chosen. |
| `IsInvalid` | `bool` |  | attribute `invalid` | Shows the invalid state and sets aria-invalid; set by pk-field or pk-form (or by a Blazor EditContext). |
| `AriaLabel` | `string?` |  | attribute `label` | The accessible name of the field and of the popup. pk-field fills it from its own label when this is empty. |
| `Open` | `bool` |  | attribute `open` | Whether the popup is open. Two-way: @bind-Open. |
| `OpenChanged` | `EventCallback<bool>` |  | two-way pair of `Open` | Raised when Open changes (two-way binding: `@bind-Open`). |
| `EmptyContent` | `RenderFragment?` |  | slot `empty` | Content for the popup's empty state (no rows, nothing searched); replaces the empty prop. Read when the popup first opens. The popup's empty state; read when the popup first opens. |
| `NoResultsContent` | `RenderFragment?` |  | slot `no-results` | Content for the popup when a search or filter matches nothing; replaces the noResults prop. Read when the popup first opens. The popup when a search or filter matches nothing; read when the popup first opens. |
| `Load` | `Func<PkListRequest, Task<PkListResult<TItem>>>?` |  |  | Loads one page of the popup table: the search, the sort, the 1-based page and the page size (PkListRequest) in, the items of that page and the total of the searched list out. A request a newer one replaces has its CancellationToken cancelled. |
| `Resolve` | `Func<IReadOnlyList<string>, Task<IReadOnlyDictionary<string, string>>>?` |  |  | Asked once, with every key that has no label yet, to name stored keys (the element calls it, not you); returns key to label. |
| `Columns` | `IReadOnlyList<PkTableColumn<TItem>>` |  |  | The columns of the popup table. |
| `IdOf` | `Func<TItem, string>?` |  |  | The key of an item: what Value and Values hold. |
| `LabelOf` | `Func<TItem, string>?` |  |  | The text the field and the chips show for an item; default its key. |
| `PageSize` | `int` |  | attribute `page-size` | The popup table's page size (initial only). The page size of the popup table (initial). Default 10. |
| `Filters` | `IReadOnlyList<PkFilterField>?` |  | attribute `filters` | The popup table's filter fields, as pk-data-table's `filters`: [{ key, label, type?, options? }]. Filter fields above the popup table; each value reaches Load in PkListRequest.Filters (a multiselect in MultiFilters). |
| `Description` | `string?` |  | attribute `description` | Help and error text, exposed as aria-description; pk-field fills it. |
| `SearchDebounce` | `int` |  | attribute `search-debounce` | Milliseconds the popup's search box waits after the last keystroke before searching. |
| `OnInput` | `EventCallback<ChangeEventArgs>` |  | event `input` | The value changed (native, composed). Read event.target.value. |
| `OnChange` | `EventCallback<ChangeEventArgs>` |  | event `change` | The reader picked a row (native, composed). |
| `ValueChanged` | `EventCallback<string?>` |  | two-way pair of `Value` | Raised when Value changes (two-way binding: `@bind-Value`). |
| `ValueExpression` | `Expression<Func<string?>>?` |  |  | The expression that names the bound field (`@bind-Value` sets it); lets the control take part in an `EditForm`: validation state and modified tracking. |
| `ValuesExpression` | `Expression<Func<IReadOnlyList<string>?>>?` |  |  | The expression that names the bound list (`@bind-Values` sets it); it names the EditContext field in place of ValueExpression. |

Two-way binding: `@bind-Values`, `@bind-Open`, `@bind-Value`.

**Event args**

| Event | Args class | Fields |
|---|---|---|
| `pk-lookup-select` | `PkLookupSelectEventArgs` | Value: string?, Label: string?, Row: JsonElement? |
| `pk-lookup-toggle` | `PkLookupToggleEventArgs` | Open: bool? |
| `pk-values-change` | `PkValuesChangeEventArgs` | Values: string[]?, Labels: string[]? |

Element details (parts, CSS custom properties, methods, accessibility): `pk-lookup-picker` in the `plainkit-sdk` skill.

## `PkMarkdownEditor`

`<pk-markdown-editor>`: **Markdown editor** (Form controls). A field for writing Markdown: a real textarea whose value is the Markdown text, a formatting toolbar (bold, italic, heading, quote, bulleted and numbered lists, link) and a Write / Preview switch. The preview is built from the parsed text with DOM calls only: raw HTML is shown as text and a link must be http, https, mailto or a relative address. Form-associated like pk-textarea. The Markdown subset is paragraphs, bold, italic, code, fenced code, headings 1 to 3, quotes, lists and links; the same parser and renderer are in js/markdown/ for showing stored text elsewhere (never write the value into markup yourself).

**Parameters**

| Parameter | Type | Enum values | Sets | Description |
|---|---|---|---|---|
| `Value` | `string?` |  | attribute `value` | The Markdown text; what the form submits. A form reset sets it back to its initial value without raising pk-change, as a native control does. |
| `Name` | `string?` |  | attribute `name` | The form field name. |
| `Placeholder` | `string?` |  | attribute `placeholder` | Hint shown while empty. |
| `Label` | `string?` |  | attribute `label` | The accessible name of the writing area. pk-field fills it from its own label when this is empty. |
| `Description` | `string?` |  | attribute `description` | Help and error text, exposed as aria-description; pk-field fills it. |
| `Disabled` | `bool` |  | attribute `disabled` | Blocks editing and commands and takes the toolbar out of the tab order. |
| `ReadOnly` | `bool` |  | attribute `readonly` | The text can be read, selected and previewed, but not edited; the toolbar does nothing. |
| `Required` | `bool` |  | attribute `required` | The form cannot submit while the text is empty. |
| `MaxLength` | `string?` |  | attribute `maxlength` | Maximum text length; a command that would exceed it does nothing. |
| `Rows` | `int` |  | attribute `rows` | Visible rows of the writing area. |
| `Mode` | `MarkdownEditorMode?` | `Write` `Preview` | attribute `mode` | Which pane shows: write or preview. The Write / Preview tabs change it. |
| `Layout` | `MarkdownEditorLayout?` | `Tabs` `Split` | attribute `layout` | tabs: one pane at a time. split: write and preview side by side while the field is at least 640px wide (the tabs return when narrower). |
| `Toolbar` | `string?` |  | attribute `toolbar` | The toolbar commands, space separated, in order: bold, italic, heading, quote, ul, ol, link. Enter in a list continues it (and ends it on an empty item); pasting an http, https or mailto address over selected text makes it a link. Ctrl/Cmd+B, I and K work in the textarea for the commands that are listed. |
| `OnInput` | `EventCallback<ChangeEventArgs>` |  | event `input` | The text changed by typing (native, composed). |
| `OnChange` | `EventCallback<ChangeEventArgs>` |  | event `change` | The user left the field after editing (native). |
| `ValueChanged` | `EventCallback<string?>` |  | two-way pair of `Value` | Raised when Value changes (two-way binding: `@bind-Value`). |
| `ValueExpression` | `Expression<Func<string?>>?` |  |  | The expression that names the bound field (`@bind-Value` sets it); lets the control take part in an `EditForm`: validation state and modified tracking. |

Two-way binding: `@bind-Value`.

**Event args**

| Event | Args class | Fields |
|---|---|---|
| `pk-change` | `PkChangeEventArgs` | Checked: bool?, Index: double?, Value: string?, Label: string?, Previous: string? |

Element details (parts, CSS custom properties, methods, accessibility): `pk-markdown-editor` in the `plainkit-sdk` skill.

## `PkOtpInput`

`<pk-otp-input>`: **OTP input** (Form controls). A one-time code or PIN as a row of cells: typing advances, Backspace steps back, a pasted or autofilled code spreads across the cells, and completion is an event.

**Parameters**

| Parameter | Type | Enum values | Sets | Description |
|---|---|---|---|---|
| `Value` | `string?` |  | attribute `value` | The code typed so far. A form reset sets it back to its initial value without raising the commit event, as a native control does: pk-form raises pk-reset after it, so a host that mirrors the value reads it again there. A browser state restore also sets it silently. |
| `Length` | `int` |  | attribute `length` | Number of cells. |
| `Type` | `OtpInputType?` | `Numeric` `Alnum` `Any` | attribute `type` | The alphabet: digits, letters and digits, or anything. |
| `SeparatorAt` | `int` |  | attribute `separator-at` | Puts a dash after this many cells (0 for none). |
| `Disabled` | `bool` |  | attribute `disabled` | Blocks interaction; also set by a disabled fieldset. |
| `IsInvalid` | `bool` |  | attribute `invalid` | Shows the invalid state and sets aria-invalid; set by pk-field or pk-form (or by a Blazor EditContext). |
| `AriaLabel` | `string?` |  | attribute `label` | The accessible name (aria-label). pk-field fills it from its own label when this is empty. |
| `Name` | `string?` |  | attribute `name` | The form field name. |
| `Description` | `string?` |  | attribute `description` | Help and error text, exposed as aria-description; pk-field fills it. |
| `Required` | `bool` |  | attribute `required` | The form cannot be submitted while the value is empty. |
| `OnComplete` | `EventCallback<PkOtpCompleteEventArgs>` |  | event `pk-otp-complete` | Every cell is filled. |
| `OnInput` | `EventCallback<ChangeEventArgs>` |  | event `input` | The value changed (native, composed: bubbles out of the shadow root). Read event.target.value. |
| `OnChange` | `EventCallback<ChangeEventArgs>` |  | event `change` | The user committed the value (re-dispatched from the inner control, composed). |
| `ValueChanged` | `EventCallback<string?>` |  | two-way pair of `Value` | Raised when Value changes (two-way binding: `@bind-Value`). |
| `ValueExpression` | `Expression<Func<string?>>?` |  |  | The expression that names the bound field (`@bind-Value` sets it); lets the control take part in an `EditForm`: validation state and modified tracking. |

Two-way binding: `@bind-Value`.

**Event args**

| Event | Args class | Fields |
|---|---|---|
| `pk-otp-change` | `PkOtpChangeEventArgs` | Value: string? |
| `pk-otp-complete` | `PkOtpCompleteEventArgs` | Value: string? |

Element details (parts, CSS custom properties, methods, accessibility): `pk-otp-input` in the `plainkit-sdk` skill.

## `PkPropertyGrid`

`<pk-property-grid>`: **Property grid** (Form controls). A property inspector: fields in collapsible groups (text, number, unit, range, colour, select, switch), each a labelled real control, with per-property validation and a pk-property-change event. Uses the same field vocabulary as pk-settings-page.

**Parameters**

| Parameter | Type | Enum values | Sets | Description |
|---|---|---|---|---|
| `Config` | `object?` |  | attribute `config` | { groups: [{ heading, collapsed?, fields: [{ key, type: 'text'\|'number'\|'unit'\|'range'\|'color'\|'select'\|'switch', label, required?, disabled?, hidden?, visibleWhen?, options?, units?, min?, max?, step? }] }] }. A unit property is a number with a unit picker: units is a list (default ['px']), its value is { value, unit } and min/max apply to the number (the message names the unit). A select's options are [{ value, label? }] or plain strings; range is a pk-range slider with its value shown, color is a #rrggbb text field with a swatch. visibleWhen is { key, equals } or { key, in: [...] } against the current values and hides the property (and skips its validation) when false. Labels sit beside the value once the grid is 480px wide, above it otherwise. Sent as a JSON attribute: { groups: [{ heading, collapsed?, fields: [{ key, type (text, number, unit, range, color, select, switch), label, required?, disabled?, hidden?, visibleWhen?, options?, units?, min?, max?, step? }] }] }. |
| `Values` | `object?` |  | attribute `values` | The property values keyed by field key; set again to update the controls (for example when the selected object changes). Sent as a JSON attribute: the property values keyed by field key. |
| `ValuesChanged` | `EventCallback<string?>` |  | two-way pair of `Values` | Raised when Values changes (two-way binding: `@bind-Values`). |
| `Errors` | `object?` |  | attribute `errors` | Host-side validation messages keyed by field key (for example from a server); shown under the property and marking it invalid. Built-in rules (required, number min/max) apply as well. Sent as a JSON attribute: host-side validation messages keyed by field key. |
| `State` | `object?` |  | attribute `state` | Live per-property state keyed by field key: { key: { disabled?, hidden? } }. Set again to enable, disable, show or hide a property without rebuilding the grid; hidden here overrides visibleWhen. Sent as a JSON attribute: live per-property { disabled?, hidden? } keyed by field key. |
| `Disabled` | `bool` |  | attribute `disabled` | Disables every property (a field's own disabled: true stays disabled either way). |
| `OnPropertyChange` | `EventCallback<PkPropertyChangeEventArgs>` |  |  | The user committed a new value for one property; carries every current value and whether all properties are valid. |

Two-way binding: `@bind-Values`.

**Event args**

| Event | Args class | Fields |
|---|---|---|
| `pk-property-change` | `PkPropertyChangeEventArgs` | Key: string?, Value: JsonElement?, Values: JsonElement?, Valid: bool? |

Element details (parts, CSS custom properties, methods, accessibility): `pk-property-grid` in the `plainkit-sdk` skill.

## `PkRadioGroup`

`<pk-radio-group>`: **Radio group** (Form controls). One choice from a few options, as radios or as a segmented bar. The options are its own option children; the radios are native inputs, so arrow keys and grouping are the browser's.

**Parameters**

| Parameter | Type | Enum values | Sets | Description |
|---|---|---|---|---|
| `Value` | `string?` |  | attribute `value` | The current value; what the form submits. A form reset sets it back to its initial value without raising the commit event, as a native control does: pk-form raises pk-reset after it, so a host that mirrors the value reads it again there. A browser state restore also sets it silently. |
| `Name` | `string?` |  | attribute `name` | The form field name. |
| `Label` | `string?` |  | attribute `label` | The accessible name (aria-label). pk-field fills it from its own label when this is empty. |
| `Disabled` | `bool` |  | attribute `disabled` | Blocks interaction; also set by a disabled fieldset. |
| `Required` | `bool` |  | attribute `required` | The form cannot be submitted while the value is empty. |
| `IsInvalid` | `bool` |  | attribute `invalid` | Shows the invalid state and sets aria-invalid; set by pk-field or pk-form (or by a Blazor EditContext). |
| `Variant` | `RadioGroupVariant?` | `Radio` `Segmented` | attribute `variant` | radio draws a list of radios; segmented draws one bar of segments. |
| `Direction` | `RadioGroupDirection?` | `Vertical` `Horizontal` | attribute `direction` | Radio variant: stacked or in a wrapping row. |
| `Fill` | `bool` |  | attribute `fill` | Segmented variant: spread the segments across the full width. |
| `Description` | `string?` |  | attribute `description` | Help and error text, exposed as aria-description; pk-field fills it. |
| `OnInput` | `EventCallback<ChangeEventArgs>` |  | event `input` | The value changed (native, composed: bubbles out of the shadow root). Read event.target.value. |
| `OnChange` | `EventCallback<ChangeEventArgs>` |  | event `change` | The user committed the value (re-dispatched from the inner control, composed). |
| `ChildContent` | `RenderFragment?` |  | default slot | option elements (value, disabled and text). |
| `ValueChanged` | `EventCallback<string?>` |  | two-way pair of `Value` | Raised when Value changes (two-way binding: `@bind-Value`). |
| `ValueExpression` | `Expression<Func<string?>>?` |  |  | The expression that names the bound field (`@bind-Value` sets it); lets the control take part in an `EditForm`: validation state and modified tracking. |

Two-way binding: `@bind-Value`.

**Event args**

| Event | Args class | Fields |
|---|---|---|
| `pk-value-change` | `PkValueChangeEventArgs` | Value: string?, Values: string[]? |

Element details (parts, CSS custom properties, methods, accessibility): `pk-radio-group` in the `plainkit-sdk` skill.

## `PkRange`

`<pk-range>`: **Range** (Form controls). A slider, or with dual a minimum and maximum slider, drawn from tokens with a live value output.

**Parameters**

| Parameter | Type | Enum values | Sets | Description |
|---|---|---|---|---|
| `Value` | `double` |  | attribute `value` | Single mode: the value. A form reset sets it back to its initial value without raising the commit event, as a native control does: pk-form raises pk-reset after it, so a host that mirrors the value reads it again there. A browser state restore also sets it silently. |
| `ValueLow` | `double` |  | attribute `value-low` | Dual mode: the low value. |
| `ValueHigh` | `double` |  | attribute `value-high` | Dual mode: the high value. |
| `Min` | `double` |  | attribute `min` | Lowest value. |
| `Max` | `double` |  | attribute `max` | Highest value. |
| `Step` | `double` |  | attribute `step` | Increment. |
| `Dual` | `bool` |  | attribute `dual` | Two thumbs: a low and a high value; the low thumb never passes the high one. |
| `Label` | `string?` |  | attribute `label` | The accessible name (aria-label). pk-field fills it from its own label when this is empty. |
| `Disabled` | `bool` |  | attribute `disabled` | Blocks interaction; also set by a disabled fieldset. |
| `ShowOutput` | `bool` |  | attribute `output` | Shows the current value under the slider. |
| `Name` | `string?` |  | attribute `name` | The form field name. |
| `Description` | `string?` |  | attribute `description` | Help and error text, exposed as aria-description; pk-field fills it. |
| `OnInput` | `EventCallback<ChangeEventArgs>` |  | event `input` | The value changed (native, composed: bubbles out of the shadow root). Read event.target.value. |
| `OnChange` | `EventCallback<ChangeEventArgs>` |  | event `change` | The user committed the value (re-dispatched from the inner control, composed). |
| `ValueChanged` | `EventCallback<double>` |  | two-way pair of `Value` | Raised when Value changes (two-way binding: `@bind-Value`). |
| `ValueExpression` | `Expression<Func<double>>?` |  |  | The expression that names the bound field (`@bind-Value` sets it); lets the control take part in an `EditForm`: validation state and modified tracking. |

Two-way binding: `@bind-Value`.

**Event args**

| Event | Args class | Fields |
|---|---|---|
| `pk-range` | `PkRangeEventArgs` | Value: double?, Low: double?, High: double? |

Element details (parts, CSS custom properties, methods, accessibility): `pk-range` in the `plainkit-sdk` skill.

## `PkRating`

`<pk-rating>`: **Rating** (Form controls). A whole-star rating input (radios underneath), and a compact read-only display form.

**Parameters**

| Parameter | Type | Enum values | Sets | Description |
|---|---|---|---|---|
| `Value` | `int` |  | attribute `value` | The rating, 0 for none. A form reset sets it back to its initial value without raising the commit event, as a native control does: pk-form raises pk-reset after it, so a host that mirrors the value reads it again there. A browser state restore also sets it silently. |
| `Max` | `int` |  | attribute `max` | Number of stars. |
| `ReadOnly` | `bool` |  | attribute `readonly` | The display form: not interactive, exposed as an image with a text alternative. |
| `Label` | `string?` |  | attribute `label` | The accessible name (aria-label). pk-field fills it from its own label when this is empty. |
| `Disabled` | `bool` |  | attribute `disabled` | Blocks interaction; also set by a disabled fieldset. |
| `Name` | `string?` |  | attribute `name` | The form field name. |
| `OnInput` | `EventCallback<ChangeEventArgs>` |  | event `input` | The value changed (native, composed: bubbles out of the shadow root). Read event.target.value. |
| `OnChange` | `EventCallback<ChangeEventArgs>` |  | event `change` | The user committed the value (re-dispatched from the inner control, composed). |
| `ValueChanged` | `EventCallback<int>` |  | two-way pair of `Value` | Raised when Value changes (two-way binding: `@bind-Value`). |
| `ValueExpression` | `Expression<Func<int>>?` |  |  | The expression that names the bound field (`@bind-Value` sets it); lets the control take part in an `EditForm`: validation state and modified tracking. |

Two-way binding: `@bind-Value`.

**Event args**

| Event | Args class | Fields |
|---|---|---|
| `pk-rating-change` | `PkRatingChangeEventArgs` | Value: double? |

Element details (parts, CSS custom properties, methods, accessibility): `pk-rating` in the `plainkit-sdk` skill.

## `PkSelect`

`<pk-select>`: **Select** (Form controls). The browser select in the same skin as the text input. Its options are its own option and optgroup children; a phone shows its native picker.

**Parameters**

| Parameter | Type | Enum values | Sets | Description |
|---|---|---|---|---|
| `Value` | `string?` |  | attribute `value` | The current value; what the form submits. A form reset or browser restore sets it silently, as a native control does (pk-form raises pk-reset after a reset). |
| `Name` | `string?` |  | attribute `name` | The form field name. |
| `Disabled` | `bool` |  | attribute `disabled` | Blocks interaction; also set by a disabled fieldset. |
| `Required` | `bool` |  | attribute `required` | The form cannot be submitted while the value is empty. |
| `Label` | `string?` |  | attribute `label` | The accessible name (aria-label). pk-field fills it from its own label when this is empty. |
| `ShowLabel` | `bool` |  | attribute `show-label` | Shows label as visible text above the field (linked to it), for use without a pk-field. |
| `IsInvalid` | `bool` |  | attribute `invalid` | Shows the invalid state and sets aria-invalid; set by pk-field or pk-form (or by a Blazor EditContext). |
| `Width` | `string?` |  | attribute `width` | Width: xs to 2xl, or a CSS length. |
| `KeepUnknownValue` | `bool` |  | attribute `keep-unknown-value` | When the value is not offered by any option (a saved id whose list has not loaded, an option since retired), keep it: a stand-in option holding the value is added first and selected, so the control never shows a value it does not hold and a save does not write the first option back. Single select only. |
| `UnknownValueLabel` | `string?` |  | attribute `unknown-value-label` | The text of the stand-in option added by keepUnknownValue. Empty shows the value itself. The option carries data-pk-unknown. |
| `Multiple` | `bool` |  | attribute `multiple` | Allows several selections (value is comma-separated with a comma inside an option value written as a backslash and a comma, a backslash before a comma or backslash doubled; the form submits one entry each). |
| `Options` | `IReadOnlyList<PkSelectOption>?` |  | attribute `options` | Options as data: a flat array of { value, label, disabled? }, a plain array of strings, or grouped as [{ group, options: [...] }]. Rendered into the inner select. When set (non-empty), it wins over slotted option/optgroup children and a warning is logged once. Sent as a JSON attribute ([{ value, label, disabled }], camelCase). When set (non-empty), it wins over ChildContent's option/optgroup markup and a warning is logged once. Grouped options are not covered by this typed parameter; build the options attribute by hand for that shape. |
| `Description` | `string?` |  | attribute `description` | Help and error text, exposed as aria-description; pk-field fills it. |
| `Warning` | `bool` |  | attribute `warning` | Shows the warning state (a value the user may want to check). |
| `IsValid` | `bool` |  | attribute `valid` | Shows the valid state. |
| `OnInput` | `EventCallback<ChangeEventArgs>` |  | event `input` | The value changed (native, composed: bubbles out of the shadow root). Read event.target.value. |
| `OnChange` | `EventCallback<ChangeEventArgs>` |  | event `change` | The user committed the value (re-dispatched from the inner control, composed). |
| `ChildContent` | `RenderFragment?` |  | default slot | option and optgroup elements; ignored while options is set. |
| `ValueChanged` | `EventCallback<string?>` |  | two-way pair of `Value` | Raised when Value changes (two-way binding: `@bind-Value`). |
| `ValueExpression` | `Expression<Func<string?>>?` |  |  | The expression that names the bound field (`@bind-Value` sets it); lets the control take part in an `EditForm`: validation state and modified tracking. |
| `Values` | `IReadOnlyList<string>?` |  |  | Value as a list (typed: no comma-joining or escaping in the host); when set it is used instead of Value. |
| `ValuesChanged` | `EventCallback<IReadOnlyList<string>?>` |  | two-way pair of `Values` | Raised when the list changes (two-way binding: `@bind-Values`). |
| `ValuesExpression` | `Expression<Func<IReadOnlyList<string>?>>?` |  |  | The expression that names the bound list (`@bind-Values` sets it); it names the EditContext field in place of ValueExpression. |

Two-way binding: `@bind-Value`, `@bind-Values`.

**Event args**

| Event | Args class | Fields |
|---|---|---|
| `pk-value-change` | `PkValueChangeEventArgs` | Value: string?, Values: string[]? |

Element details (parts, CSS custom properties, methods, accessibility): `pk-select` in the `plainkit-sdk` skill.

## `PkSelectMenu`

`<pk-select-menu>`: **Select menu** (Forms & inputs). A single-choice listbox popup that reads native option children, so it degrades to nothing worse than a list; form-associated, keyboard driven with typeahead.

**Parameters**

| Parameter | Type | Enum values | Sets | Description |
|---|---|---|---|---|
| `Value` | `string?` |  | attribute `value` | Selected option value. A form reset sets it back to its initial value without raising the commit event, as a native control does: pk-form raises pk-reset after it, so a host that mirrors the value reads it again there. A browser state restore also sets it silently. |
| `ValueChanged` | `EventCallback<string?>` |  | two-way pair of `Value` | Raised when Value changes (two-way binding: `@bind-Value`). |
| `Name` | `string?` |  | attribute `name` | Form field name. |
| `Placeholder` | `string?` |  | attribute `placeholder` | Shown with no selection. |
| `Open` | `bool` |  | attribute `open` | Whether the list is shown. |
| `OpenChanged` | `EventCallback<bool>` |  | two-way pair of `Open` | Raised when Open changes (two-way binding: `@bind-Open`). |
| `Disabled` | `bool` |  | attribute `disabled` | Prevents interaction |
| `Required` | `bool` |  | attribute `required` | A value is required |
| `ChildContent` | `RenderFragment?` |  | default slot | option elements. |
| `OnChange` | `EventCallback<PkChangeEventArgs>` |  | event `pk-change` | The selection changed. |
| `OnOpen` | `EventCallback` |  |  | The list opened. |
| `OnClose` | `EventCallback<PkCloseEventArgs>` |  |  | A close was asked for (Escape, outside press, choosing, the trigger). Cancelable: preventDefault keeps it open. The event can be cancelled in the browser (preventDefault); a callback cannot cancel it. |

Two-way binding: `@bind-Value`, `@bind-Open`.

**Event args**

| Event | Args class | Fields |
|---|---|---|
| `pk-change` | `PkChangeEventArgs` | Checked: bool?, Index: double?, Value: string?, Label: string?, Previous: string? |
| `pk-close` | `PkCloseEventArgs` | Reason: string? |

Element details (parts, CSS custom properties, methods, accessibility): `pk-select-menu` in the `plainkit-sdk` skill.

## `PkSwitch`

`<pk-switch>`: **Switch** (Form controls). An on/off toggle that takes part in a form: it submits its value when on and resets with the form.

**Parameters**

| Parameter | Type | Enum values | Sets | Description |
|---|---|---|---|---|
| `Checked` | `bool` |  | attribute `checked` | Whether the switch is on. A form reset sets it back to its initial value without raising the commit event, as a native control does: pk-form raises pk-reset after it, so a host that mirrors the value reads it again there. A browser state restore also sets it silently. |
| `CheckedChanged` | `EventCallback<bool>` |  | two-way pair of `Checked` | Raised with the new value of Checked (two-way: Checked follows it). |
| `Disabled` | `bool` |  | attribute `disabled` | Blocks interaction; also set by a disabled fieldset. |
| `Name` | `string?` |  | attribute `name` | The form field name. |
| `Value` | `string?` |  | attribute `value` | The value submitted while checked. |
| `IsInvalid` | `bool` |  | attribute `invalid` | Shows the invalid state (a red ring) and sets aria-invalid. |
| `Size` | `SwitchSize?` | `Sm` `Md` `Lg` | attribute `size` | Track size. |
| `LabelPosition` | `SwitchLabelPosition?` | `End` `Start` `Between` | attribute `label-position` | end puts the label after the switch, start before it, between pushes them to opposite edges of the row. |
| `ChildContent` | `RenderFragment?` |  | default slot | The label. |
| `CheckedExpression` | `Expression<Func<bool>>?` |  |  | The expression that names the bound field (`@bind-Checked` sets it); lets the control take part in an `EditForm`: validation state and modified tracking. |

Two-way binding: `@bind-Checked`.

**Event args**

| Event | Args class | Fields |
|---|---|---|
| `pk-change` | `PkChangeEventArgs` | Checked: bool?, Index: double?, Value: string?, Label: string?, Previous: string? |

Element details (parts, CSS custom properties, methods, accessibility): `pk-switch` in the `plainkit-sdk` skill.

## `PkTagInput`

`<pk-tag-input>`: **Tag input** (Form controls). Free-text tags typed into one control: Enter or a separator adds, paste splits, Backspace in an empty field removes the last, duplicates and a maximum are handled.

**Parameters**

| Parameter | Type | Enum values | Sets | Description |
|---|---|---|---|---|
| `Value` | `string?` |  | attribute `value` | The tags, comma-joined (a comma inside a tag is written as a backslash and a comma; read the tags property for the list). A form reset sets it back to its initial value without raising the commit event, as a native control does: pk-form raises pk-reset after it, so a host that mirrors the value reads it again there. A browser state restore also sets it silently. |
| `Placeholder` | `string?` |  | attribute `placeholder` | Hint shown in the empty field. |
| `Disabled` | `bool` |  | attribute `disabled` | Blocks interaction; also set by a disabled fieldset. |
| `Required` | `bool` |  | attribute `required` | The form cannot be submitted while the value is empty. |
| `IsInvalid` | `bool` |  | attribute `invalid` | Shows the invalid state and sets aria-invalid; set by pk-field or pk-form (or by a Blazor EditContext). |
| `Separators` | `string?` |  | attribute `separators` | Characters that end a tag (besides Enter). |
| `Max` | `int` |  | attribute `max` | Most tags allowed; 0 means no limit. |
| `AriaLabel` | `string?` |  | attribute `label` | The accessible name (aria-label). pk-field fills it from its own label when this is empty. |
| `LockedTags` | `string?` |  | attribute `locked-tags` | Always-present tags, comma-joined, shown before the editable ones. Rendered without a remove button, excluded from value, from the form value and from Backspace removal; a locked tag with the same text as an editable one is still shown twice. Set lockedTitle for why they can't be removed. |
| `LockedTitle` | `string?` |  | attribute `locked-title` | Tooltip (title attribute) on every locked tag. |
| `Name` | `string?` |  | attribute `name` | The form field name. |
| `Description` | `string?` |  | attribute `description` | Help and error text, exposed as aria-description; pk-field fills it. |
| `AllowDuplicates` | `bool` |  | attribute `allow-duplicates` | Allows the same tag twice (case-insensitive by default). |
| `OnInput` | `EventCallback<ChangeEventArgs>` |  | event `input` | The value changed (native, composed: bubbles out of the shadow root). Read event.target.value. |
| `OnChange` | `EventCallback<ChangeEventArgs>` |  | event `change` | The user committed the value (re-dispatched from the inner control, composed). |
| `ValueChanged` | `EventCallback<string?>` |  | two-way pair of `Value` | Raised when Value changes (two-way binding: `@bind-Value`). |
| `ValueExpression` | `Expression<Func<string?>>?` |  |  | The expression that names the bound field (`@bind-Value` sets it); lets the control take part in an `EditForm`: validation state and modified tracking. |
| `Values` | `IReadOnlyList<string>?` |  |  | Value as a list (typed: no comma-joining or escaping in the host); when set it is used instead of Value. |
| `ValuesChanged` | `EventCallback<IReadOnlyList<string>?>` |  | two-way pair of `Values` | Raised when the list changes (two-way binding: `@bind-Values`). |
| `ValuesExpression` | `Expression<Func<IReadOnlyList<string>?>>?` |  |  | The expression that names the bound list (`@bind-Values` sets it); it names the EditContext field in place of ValueExpression. |

Two-way binding: `@bind-Value`, `@bind-Values`.

**Event args**

| Event | Args class | Fields |
|---|---|---|
| `pk-tags-change` | `PkTagsChangeEventArgs` | Value: string?, Values: string[]? |

Element details (parts, CSS custom properties, methods, accessibility): `pk-tag-input` in the `plainkit-sdk` skill.

## `PkTextarea`

`<pk-textarea>`: **Textarea** (Form controls). A multi-line control that can grow with its content up to a cap.

**Parameters**

| Parameter | Type | Enum values | Sets | Description |
|---|---|---|---|---|
| `Value` | `string?` |  | attribute `value` | The current value; what the form submits. A form reset sets it back to its initial value without raising the commit event, as a native control does: pk-form raises pk-reset after it, so a host that mirrors the value reads it again there. A browser state restore also sets it silently. |
| `Name` | `string?` |  | attribute `name` | The form field name. |
| `Placeholder` | `string?` |  | attribute `placeholder` | Hint shown while empty. |
| `AriaLabel` | `string?` |  | attribute `label` | The accessible name (aria-label). pk-field fills it from its own label when this is empty. |
| `Disabled` | `bool` |  | attribute `disabled` | Blocks interaction; also set by a disabled fieldset. |
| `ReadOnly` | `bool` |  | attribute `readonly` | The value can be read but not edited. |
| `Required` | `bool` |  | attribute `required` | The form cannot be submitted while the value is empty. |
| `IsInvalid` | `bool` |  | attribute `invalid` | Shows the invalid state and sets aria-invalid; set by pk-field or pk-form (or by a Blazor EditContext). |
| `Font` | `PkTextareaFont?` | `Inherit` `Sans` `Mono` | attribute `font` | Font family of the text: sans or mono (for code, queries, ids). Default inherit. |
| `Rows` | `int` |  | attribute `rows` | Visible rows of a fixed-height textarea. |
| `MaxLength` | `string?` |  | attribute `maxlength` | Maximum text length. |
| `ShowLabel` | `bool` |  | attribute `show-label` | Shows label as visible text above the field (linked to it), for use without a pk-field. |
| `AutoGrow` | `bool` |  | attribute `autogrow` | Grows with the content instead of scrolling. |
| `MaxHeight` | `int` |  | attribute `max-height` | Auto-grow cap in pixels; 0 means no cap and the box scrolls beyond it otherwise. |
| `Description` | `string?` |  | attribute `description` | Help and error text, exposed as aria-description; pk-field fills it. |
| `Warning` | `bool` |  | attribute `warning` | Shows the warning state (a value the user may want to check). |
| `IsValid` | `bool` |  | attribute `valid` | Shows the valid state. |
| `MinLength` | `string?` |  | attribute `minlength` | Minimum text length. |
| `OnInput` | `EventCallback<ChangeEventArgs>` |  | event `input` | The value changed (native, composed: bubbles out of the shadow root). Read event.target.value. |
| `OnChange` | `EventCallback<ChangeEventArgs>` |  | event `change` | The user committed the value (re-dispatched from the inner control, composed). |
| `ValueChanged` | `EventCallback<string?>` |  | two-way pair of `Value` | Raised when Value changes (two-way binding: `@bind-Value`). |
| `ValueExpression` | `Expression<Func<string?>>?` |  |  | The expression that names the bound field (`@bind-Value` sets it); lets the control take part in an `EditForm`: validation state and modified tracking. |

Two-way binding: `@bind-Value`.

**Event args**

| Event | Args class | Fields |
|---|---|---|
| `pk-value-change` | `PkValueChangeEventArgs` | Value: string?, Values: string[]? |

Element details (parts, CSS custom properties, methods, accessibility): `pk-textarea` in the `plainkit-sdk` skill.

## `PkUnitInput`

`<pk-unit-input>`: **Unit input** (Form controls). A number and a unit select in one field for lengths such as 1.5rem or 24px; the value is the two joined, and a value with a unit outside the list keeps its unit.

**Parameters**

| Parameter | Type | Enum values | Sets | Description |
|---|---|---|---|---|
| `Value` | `string?` |  | attribute `value` | The number and unit joined, for example 1.5rem or 12px (empty until there is a number); what the form submits. A value that is not a number with a unit (auto, calc(...)) leaves the number field empty and is kept until the user edits. A form reset sets it back to its initial value without raising the commit event, as a native control does: pk-form raises pk-reset after it, so a host that mirrors the value reads it again there. A browser state restore also sets it silently. |
| `ValueChanged` | `EventCallback<string?>` |  | two-way pair of `Value` | Raised when Value changes (two-way binding: `@bind-Value`). |
| `Name` | `string?` |  | attribute `name` | The form field name. |
| `Units` | `string?` |  | attribute `units` | The units the select offers, comma or space separated; the first is used until a value or the user picks another. A value whose unit is not listed adds that unit to the select. |
| `Placeholder` | `string?` |  | attribute `placeholder` | Hint shown in the number field while it is empty. |
| `AriaLabel` | `string?` |  | attribute `label` | The accessible name (aria-label) of the number field; the unit select is named "<label> unit". pk-field fills it from its own label when this is empty. |
| `ShowLabel` | `bool` |  | attribute `show-label` | Shows label as visible text above the field (linked to it), for use without a pk-field. |
| `Disabled` | `bool` |  | attribute `disabled` | Blocks interaction; also set by a disabled fieldset. |
| `ReadOnly` | `bool` |  | attribute `readonly` | Shows the value but does not let it change (the unit select is disabled too). |
| `Required` | `bool` |  | attribute `required` | The form cannot be submitted while the number is empty. |
| `IsInvalid` | `bool` |  | attribute `invalid` | Shows the invalid state and sets aria-invalid; set by pk-field or pk-form (or by a Blazor EditContext). |
| `Min` | `string?` |  | attribute `min` | Lowest number (the number, whatever the unit). |
| `Max` | `string?` |  | attribute `max` | Highest number. |
| `Step` | `string?` |  | attribute `step` | The number's step: any (the default) allows decimals, or a size such as 0.25 that the arrow keys move by. |
| `Description` | `string?` |  | attribute `description` | Help and error text, exposed as aria-description; pk-field fills it. |
| `OnInput` | `EventCallback<ChangeEventArgs>` |  | event `input` | The number was edited (native, composed: bubbles out of the shadow root). Read the value from the element. |
| `OnChange` | `EventCallback<ChangeEventArgs>` |  | event `change` | The user committed the number or picked another unit (re-dispatched from the inner control, composed). |

Two-way binding: `@bind-Value`.

**Event args**

| Event | Args class | Fields |
|---|---|---|
| `pk-value-change` | `PkValueChangeEventArgs` | Value: string?, Values: string[]? |

Element details (parts, CSS custom properties, methods, accessibility): `pk-unit-input` in the `plainkit-sdk` skill.
