diff --git a/Documentation/CommandForm/radio-button-field.md b/Documentation/CommandForm/radio-button-field.md
new file mode 100644
index 0000000..8957e8f
--- /dev/null
+++ b/Documentation/CommandForm/radio-button-field.md
@@ -0,0 +1,30 @@
+# RadioButtonField
+
+`RadioButtonField` renders a single PrimeReact `RadioButton` that sets the bound command property to a specific value when selected. Use multiple `RadioButtonField` components bound to the same property to form a radio group.
+
+## Usage
+
+```tsx
+import { CommandDialog } from '@cratis/components';
+import { RadioButtonField } from '@cratis/components/CommandForm';
+
+ setVisible(false)}>
+ value={c => c.size} buttonValue="small" label="Small" />
+ value={c => c.size} buttonValue="medium" label="Medium" />
+ value={c => c.size} buttonValue="large" label="Large" />
+
+```
+
+## Props
+
+| Prop | Type | Default | Description |
+|------|------|---------|-------------|
+| `value` | `(instance: TCommand) => unknown` | — | **Required.** Accessor function that returns the bound property from the command instance. Pass the command type as the generic parameter for full type safety. |
+| `buttonValue` | `string \| number` | — | **Required.** The value this radio button represents. When selected, the command property is set to this value. |
+| `label` | `string` | — | Text displayed inline next to the radio button. |
+
+## Behavior
+
+- Default value is an empty string.
+- The radio button is checked when the current field value equals `buttonValue`.
+- Validation state is reflected via the PrimeReact `invalid` flag on the radio button.
diff --git a/Documentation/CommandForm/radio-group-field.md b/Documentation/CommandForm/radio-group-field.md
new file mode 100644
index 0000000..0a07200
--- /dev/null
+++ b/Documentation/CommandForm/radio-group-field.md
@@ -0,0 +1,55 @@
+# RadioGroupField
+
+`RadioGroupField` renders a group of PrimeReact `RadioButton` components from an options array, allowing the user to select a single value.
+
+## Usage
+
+```tsx
+import { CommandDialog } from '@cratis/components';
+import { RadioGroupField } from '@cratis/components/CommandForm';
+
+const sizeOptions = [
+ { id: 'small', label: 'Small' },
+ { id: 'medium', label: 'Medium' },
+ { id: 'large', label: 'Large' },
+];
+
+ setVisible(false)}>
+
+ value={c => c.size}
+ options={sizeOptions}
+ optionLabel="label"
+ optionValue="id"
+ title="Size"
+ />
+
+```
+
+With horizontal layout:
+
+```tsx
+
+ value={c => c.priority}
+ options={priorityOptions}
+ optionLabel="label"
+ optionValue="id"
+ title="Priority"
+ layout="horizontal"
+/>
+```
+
+## Props
+
+| Prop | Type | Default | Description |
+|------|------|---------|-------------|
+| `value` | `(instance: TCommand) => unknown` | — | **Required.** Accessor function that returns the bound property from the command instance. Pass the command type as the generic parameter for full type safety. |
+| `options` | `Array>` | — | **Required.** Array of option objects. |
+| `optionLabel` | `string` | — | **Required.** Key in each option object to use as the display label. |
+| `optionValue` | `string` | — | **Required.** Key in each option object to use as the submitted value. |
+| `layout` | `'horizontal' \| 'vertical'` | `'vertical'` | Controls whether the radio buttons are stacked vertically or laid out in a horizontal row. |
+
+## Behavior
+
+- Default value is an empty string.
+- A radio button is checked when the current field value equals its `optionValue`.
+- Validation state is reflected via the PrimeReact `invalid` flag on all radio buttons.
diff --git a/Documentation/CommandForm/toc.yml b/Documentation/CommandForm/toc.yml
index 8584119..5e7cefb 100644
--- a/Documentation/CommandForm/toc.yml
+++ b/Documentation/CommandForm/toc.yml
@@ -16,6 +16,10 @@
href: multi-select-field.md
- name: NumberField
href: number-field.md
+- name: RadioButtonField
+ href: radio-button-field.md
+- name: RadioGroupField
+ href: radio-group-field.md
- name: SliderField
href: slider-field.md
- name: TextAreaField
diff --git a/Source/CommandForm/fields/Fields.stories.tsx b/Source/CommandForm/fields/Fields.stories.tsx
index 55fa4bc..5b2943f 100644
--- a/Source/CommandForm/fields/Fields.stories.tsx
+++ b/Source/CommandForm/fields/Fields.stories.tsx
@@ -18,7 +18,9 @@ import {
CalendarField,
ColorPickerField,
MultiSelectField,
- ChipsField
+ ChipsField,
+ RadioButtonField,
+ RadioGroupField
} from './index';
const meta: Meta = {
@@ -48,6 +50,8 @@ class FormFieldsCommand extends Command {
new PropertyDescriptor('color', String),
new PropertyDescriptor('multiSelect', Array),
new PropertyDescriptor('chips', Array),
+ new PropertyDescriptor('radioButton', String),
+ new PropertyDescriptor('radioGroup', String),
];
textInput = '';
@@ -62,6 +66,8 @@ class FormFieldsCommand extends Command {
color = '';
multiSelect: Array = [];
chips: string[] = [];
+ radioButton = '';
+ radioGroup = '';
constructor() {
super(Object, false);
@@ -84,7 +90,9 @@ class FormFieldsCommand extends Command {
'calendarDate',
'color',
'multiSelect',
- 'chips'
+ 'chips',
+ 'radioButton',
+ 'radioGroup'
];
}
}
@@ -145,6 +153,8 @@ export const AllFields: Story = {
color: '10b981',
multiSelect: ['feature1', 'feature3'],
chips: ['alpha', 'beta'],
+ radioButton: '',
+ radioGroup: '',
}}
onFieldChange={async (command, fieldName) => {
// Validate on field change
@@ -358,6 +368,43 @@ export const AllFields: Story = {
+
+