RadioButton
A single radio choice for a group that shares a name.
Playground and Examples use the shared browser runtime. For Service Studio inputs and event wiring, use Implementation and API.
Open OutSystems showcase ↗Implement RadioButton in your application
Use the same setup, screen state and event mapping workflow as the existing components. These components are included in Community 1.1.0.
A single radio choice for a group that shares a name. These components are included in @blukavantui/community 1.1.0.
Prepare your local Web project
Use a TypeScript application with a CSS-capable bundler. Install @blukavantui/community@1.1.0 from npm, or install the matching downloaded archive.
// In your test application’s package.json dependencies:
"@blukavantui/community": "1.1.0"Run npm install in that test application to install the component package. Load the theme once and the component stylesheet shown in the adapter. Create an empty host in your view:
<div id="example"></div>Mount one typed instance
This reusable adapter follows the Button and TimePicker guide pattern. Its types come from the factory, so required options stay required. Attach the host first; mount once per view and retain the handle.
import { createRadioButton } from '@blukavantui/community/radio-button'
import '@blukavantui/community/theme.css'
import '@blukavantui/community/radio-button.css'
type Options = NonNullable<Parameters<typeof createRadioButton>[1]>
type Events = NonNullable<Parameters<typeof createRadioButton>[2]>
export function mount(host: HTMLElement, options: Options, events: Events = {}) {
const instance = createRadioButton(host, options, events)
return { instance, update: (patch: Partial<Options>) => instance.update(patch), destroy: () => instance.destroy() }
}
Connect state and updates
User interaction calls Change; update() and reset() do not. Synchronize your application state after either method. Clear a stale Error before validate(), and validate again in your application before saving. These fields expose Change and Blur; TextInput also exposes Action.
The working example stores values in application variables. If the host is inside a form, a non-canceled form reset restores initial component values; synchronize your store after that reset and clear any application errors explicitly.
Coordinate a mutually exclusive choice
Use: Name, Value, Checked, Change
Give related instances one Name and distinct Value identifiers. Keep a single selected-value string in application state. When an instance emits true, set that string and update every instance’s Checked property. Browsers do not emit Change for the sibling they uncheck.
Select with a pointer and arrow keys; verify both instances and the shared state agree.
Prefer RadioGroup for data-driven choices
Use: Checked, ReadOnly
Use individual RadioButton instances for custom layouts. For one Options array and one string Change callback, use RadioGroup. ReadOnly prevents switching; Disabled removes an option from interaction.
Change unrelated labels after selection and confirm the selected option is preserved.
Use the complete working example
Save this as radio-button.ts, import its mount function and pass your attached host. It includes application state, interactive controls and a destroy handler.
Download the editable TypeScript example ↓
Complete RadioButton example
import { createRadioButton } from '@blukavantui/community/radio-button'
import '@blukavantui/community/theme.css'
import '@blukavantui/community/radio-button.css'
export function mount(host: HTMLElement) {
const root = document.createElement('fieldset')
const legend = document.createElement('legend'); legend.textContent = 'Delivery method'
const standardHost = document.createElement('div'), expressHost = document.createElement('div')
const status = document.createElement('p'); status.setAttribute('role', 'status')
const reset = document.createElement('button')
reset.type = 'button'; reset.textContent = 'Use standard delivery'
root.append(legend, standardHost, expressHost, status, reset); host.append(root)
const name = `delivery-${crypto.randomUUID()}` // Shared by this pair, unique across mounted examples.
let selected = 'standard'
function select(value: string) {
selected = value
standard.update({ Checked: selected === 'standard' })
express.update({ Checked: selected === 'express' })
status.textContent = `Selected: ${selected}`
}
const standard = createRadioButton(standardHost, {
Name: name, Value: 'standard', Label: 'Standard', Checked: true,
}, { Change(checked) { if (checked) select('standard') } })
const express = createRadioButton(expressHost, {
Name: name, Value: 'express', Label: 'Express', Checked: false,
}, { Change(checked) { if (checked) select('express') } })
// The browser does not notify the sibling that it unchecked.
const listeners = new AbortController()
reset.addEventListener('click', () => select('standard'), { signal: listeners.signal })
select(selected)
return { standard, express, destroy() {
listeners.abort(); standard.destroy(); express.destroy(); root.remove()
} }
}
Verify behavior and dispose
- Use Tab to reach the control. Space toggles choices; radio groups support arrow navigation. Inputs retain standard text-editing shortcuts.
- Check required, disabled and read-only states; verify reset and programmatic updates also synchronize your application state.
- Call the example handle’s
destroy()when the view is removed. Abort your application listeners and requests; ignore any asynchronous result after disposal. - Mount again and confirm there is one instance and one callback per interaction.
Reference the native producer
In Manage Dependencies, select RadioButton from BluKavantUi_Community_Inputs, together with the structures and public actions used by its API. Refresh existing references before publishing your consumer. Inherit the shared Community theme in your application's theme.
Place the Block in your screen
ExampleScreen — Screen (your application)
└─ ExistingLayout — referenced Layout Block instance (child of ExampleScreen)
└─ Content — existing slot on ExistingLayout
└─ ComponentRegion — Container (child of that slot)
└─ MainComponent — BluKavantUi_Community_Inputs.RadioButton Block instance (child of ComponentRegion)Reuse your screen’s existing Layout and its content slot; do not add a second layout. If your Layout names that slot differently, use its actual content slot. ComponentRegion is a new Container; MainComponent is a referenced Block instance.
Create and bind screen state
Create local variables on ExampleScreen for the values your application changes. Use the exact native types below; lists are typed OutSystems Lists, while inputs ending in Json are Text containing the documented JSON. Bind each MainComponent.Input to its matching StateInput local. Constants can instead use the default directly. Fill required data from your Aggregate or Data Action before enabling interaction.
| MainComponent input | Screen local / native type | Initial value | Purpose |
|---|---|---|---|
| Error | StateError · Text | "" | Application validation message; a non-empty value marks the control invalid. Clear it after validation succeeds. |
| Checked | StateChecked · Boolean | False | Boolean checked state. Bind a screen variable and assign the Boolean OnChange.Value back to it. |
All native input defaults
| Input | Type | Default | Required |
|---|---|---|---|
| Name | Text | "" | No |
| Label | Text | "" | No |
| Description | Text | "" | No |
| Error | Text | "" | No |
| Required | Boolean | False | No |
| Disabled | Boolean | False | No |
| ReadOnly | Boolean | False | No |
| Size | Text | "Medium" | No |
| ExtendedClass | Text | "" | No |
| Value | Text | "option" | No |
| Checked | Boolean | False | No |
| EnableMotion | Boolean | False | No |
| MotionPreference | Text | "System" | No |
| UseDefaultMotionDuration | Boolean | True | No |
| MotionDurationMs | Integer | 450 | No |
| MotionEasing | Text | "standard" | No |
| EnableRipple | Boolean | False | No |
Create the event handlers and map every argument
For each event you use, create the named screen Client Action below. Add its listed input parameters with the exact types. Select that action on MainComponent's event property, then enter each mapping explicitly. Event arguments and screen locals are different scopes.
OnBlur → HandleBlur
Raised when a field loses focus. Validate your screen state here when using validation on blur.
| Handler input | Native type | Event mapping |
|---|
Flow: Start → run your application action using the mapped event arguments → End.
OnChange → HandleChange
Raised when the user changes the value. Assign the emitted Value back to the bound screen variable.
| Handler input | Native type | Event mapping |
|---|---|---|
| RequestedValue | Boolean | RequestedValue = Value |
Flow: Start → validate the requested value; assign the corresponding screen state so the Block receives it back → End.
OnError → HandleError
Reports native runtime initialization or update errors. Show safe feedback and inspect the configuration; this is not the normal field validation event.
| Handler input | Native type | Event mapping |
|---|---|---|
| RequestedMessage | Text | RequestedMessage = Message |
Flow: Start → display the mapped error argument in your feedback region → End.
Apply the example event flow
MainComponent.OnChange → HandleChange
Map RequestedValue = Value
Start
→ Assign StateChecked = RequestedValue
→ EndKeep a radio selection synchronized
For multiple RadioButton Blocks, give them the same Name and distinct Value identifiers. Keep one selected-value Text variable in your screen. Bind each Checked to SelectedValue = that option’s value; when its OnChange.Value is True, assign that option’s value to SelectedValue. RadioGroup provides this single-value contract directly for a list of choices.
Validate before saving
These custom controls do not automatically participate in OutSystems Form.Valid. Validate your bound screen state, assign Error text for invalid fields, and call your own Server Action only when valid. Validate again on the server. Required is a runtime field requirement, not a mandatory Block input.
Verify in your consumer
Publish the consumer, supply representative data, trigger each connected event and inspect the mapped arguments. Check a failed request, a retry and leaving/reopening the screen. The table describes the native contract; the Web recipes can contain capabilities with different native names or availability. Use these native names and the API tab as the authority for Service Studio.
Shared component motion settings
Use createMotionComponents from the local bluui-community/src/component-motion.ts entry. The factories retain the component’s data, options, events and methods, and add setMotion(settings?). Create the controller with createMotionController from bluui-community/src/motion.ts.
| Setting / method | Behavior |
|---|---|
mode | inherit (default), reduced, or off. The owning controller and operating system can always reduce or disable motion. |
duration | Optional finite-transition override, 0–2000 ms. Omit for default timings; zero is immediate. Reduced caps permitted fades at 200 ms. Continuous loading retains its own cadence. |
easing | Optional standard, ease-in, ease-out, ease-in-out, linear or spring. Omit for each component's default easing. |
ui.configure(settings?) | Replace collection defaults, update existing instances and cancel their unfinished decoration. Explicit instance overrides remain. Omit settings to restore component defaults. |
component.setMotion(settings?) | Replace just this instance's overrides. Omit settings to inherit the collection again. Inputs, focus, content and actions are retained. |
ui.destroy() | Dispose owned instances and their motion before destroying the controller. No global listener is added at import time. |
Validation rejects nonfinite, negative and over-2000-ms durations before changing settings. Motion follows the existing component behavior. Grid rows need stable keys; charts update their actual data series; workflow transitions retain their approval and save contracts. Charts respect EnableAnimation: false; continuous Sparkline glow keeps its own cadence and Pause control. Ripple, glow, shimmer and page-entry helpers remain explicit additions.
Open the playground motion controls · Read the motion and OutSystems integration guide
Current playground settings
Open the playground to load the local source example.RadioButton with application state
These components are included in @blukavantui/community 1.1.0. This is the same complete example used by the implementation guide, with real controls, event handling and cleanup.
import { createRadioButton } from '@blukavantui/community/radio-button'
import '@blukavantui/community/theme.css'
import '@blukavantui/community/radio-button.css'
export function mount(host: HTMLElement) {
const root = document.createElement('fieldset')
const legend = document.createElement('legend'); legend.textContent = 'Delivery method'
const standardHost = document.createElement('div'), expressHost = document.createElement('div')
const status = document.createElement('p'); status.setAttribute('role', 'status')
const reset = document.createElement('button')
reset.type = 'button'; reset.textContent = 'Use standard delivery'
root.append(legend, standardHost, expressHost, status, reset); host.append(root)
const name = `delivery-${crypto.randomUUID()}` // Shared by this pair, unique across mounted examples.
let selected = 'standard'
function select(value: string) {
selected = value
standard.update({ Checked: selected === 'standard' })
express.update({ Checked: selected === 'express' })
status.textContent = `Selected: ${selected}`
}
const standard = createRadioButton(standardHost, {
Name: name, Value: 'standard', Label: 'Standard', Checked: true,
}, { Change(checked) { if (checked) select('standard') } })
const express = createRadioButton(expressHost, {
Name: name, Value: 'express', Label: 'Express', Checked: false,
}, { Change(checked) { if (checked) select('express') } })
// The browser does not notify the sibling that it unchecked.
const listeners = new AbortController()
reset.addEventListener('click', () => select('standard'), { signal: listeners.signal })
select(selected)
return { standard, express, destroy() {
listeners.abort(); standard.destroy(); express.destroy(); root.remove()
} }
}
Mount and dispose
Call mount after the host is attached to the document. Retain the returned handle and call destroy from your view’s unmount hook.
import { mount } from './radio-button'
const host = document.getElementById('example')
if (!host) throw new Error('Missing example host')
const view = mount(host)
// Register this with your framework/router’s unmount hook:
function disposeView() { view.destroy() }Use instance.update(patch) for changes while mounted; creating another instance on each render leaves duplicate controls.
Build with native Blocks
Configure the referenced Block in Service Studio using typed inputs, screen state and Client Actions. The Implementation tab includes the widget tree and exact event argument mappings.
Shared component motion settings
Use createMotionComponents from the local bluui-community/src/component-motion.ts entry. The factories retain the component’s data, options, events and methods, and add setMotion(settings?). Create the controller with createMotionController from bluui-community/src/motion.ts.
| Setting / method | Behavior |
|---|---|
mode | inherit (default), reduced, or off. The owning controller and operating system can always reduce or disable motion. |
duration | Optional finite-transition override, 0–2000 ms. Omit for default timings; zero is immediate. Reduced caps permitted fades at 200 ms. Continuous loading retains its own cadence. |
easing | Optional standard, ease-in, ease-out, ease-in-out, linear or spring. Omit for each component's default easing. |
ui.configure(settings?) | Replace collection defaults, update existing instances and cancel their unfinished decoration. Explicit instance overrides remain. Omit settings to restore component defaults. |
component.setMotion(settings?) | Replace just this instance's overrides. Omit settings to inherit the collection again. Inputs, focus, content and actions are retained. |
ui.destroy() | Dispose owned instances and their motion before destroying the controller. No global listener is added at import time. |
Validation rejects nonfinite, negative and over-2000-ms durations before changing settings. Motion follows the existing component behavior. Grid rows need stable keys; charts update their actual data series; workflow transitions retain their approval and save contracts. Charts respect EnableAnimation: false; continuous Sparkline glow keeps its own cadence and Pause control. Ripple, glow, shimmer and page-entry helpers remain explicit additions.
Open the playground motion controls · Read the motion and OutSystems integration guide
Current playground settings
Open the playground to load the local source example.createRadioButton
User interaction calls Change; update() and reset() do not. Synchronize your application state after either method. Clear a stale Error before validate(), and validate again in your application before saving. These fields expose Change and Blur; TextInput also exposes Action.
import { createRadioButton } from '@blukavantui/community/radio-button';
import '@blukavantui/community/radio-button.css';Load @blukavantui/community/theme.css once in your app shell.createRadioButton(host: HTMLElement, options: RadioButtonOptions, events?: FieldEvents<boolean>)These components are included in @blukavantui/community 1.1.0. Required/optional and signatures come from the 1.1.0 TypeScript source. Defaults below describe runtime behavior, which may differ from the Playground’s selected example.
Options
12| Name | Type / requirement | Usage |
|---|---|---|
Checked | boolean | undefinedOptional | Default: false. Boolean state. Change emits the new checked value, not the option’s string Value. |
Value | stringRequired | Required (use a non-empty value). HTML option value used for form submission. Change/getValue report the Boolean checked state, not this identifier. |
Id | string | undefinedOptional | Default: Generated once. Control id used for label/help association. Set when mounting; changing Id later does not replace the generated identity. |
Name | string | undefinedOptional | Default: "". HTML form field name. Supply it when using FormData. |
Label | string | undefinedOptional | Default: "". Visible accessible label. Placeholder text does not replace a label. |
Description | string | undefinedOptional | Default: "". Supporting text associated with the control through aria-describedby. |
Error | string | undefinedOptional | Default: "". Validation message and invalid appearance. Input components also set custom validity; clear Error before rechecking a corrected value. |
Required | boolean | undefinedOptional | Default: false. Enables the control’s required constraint and accessible required state. Validation still belongs to your application. |
Disabled | boolean | undefinedOptional | Default: false. Prevents interaction; disabled native form controls are omitted from FormData. |
ReadOnly | boolean | undefinedOptional | Default: false. Prevents user changes while retaining a readable value. Choice and Select controls implement this behavior themselves. |
Size | FieldSize | undefinedOptional | Default: "Medium". Small, Medium or Large. Uses the shared field sizing tokens. |
ExtendedClass | string | undefinedOptional | Default: "". Additional space-separated classes on the root. Keep application CSS scoped. |
Callbacks
2| Name | Type / requirement | Usage |
|---|---|---|
Change | ((value: boolean) => void) | undefinedOptional | Called for a user value change (including a clear action). TextInput/TextArea emit on input; choices emit on selection. update and reset do not emit Change. Synchronize your application state explicitly after programmatic changes. |
Blur | (() => void) | undefinedOptional | Called when the input loses focus. Select reports Blur when focus leaves its composite control. Use it to run application validation if desired. |
Instance methods & properties
8| Name | Signature / type | Usage |
|---|---|---|
element | HTMLElement | Root DOM element owned by the component. Mount into a real host before using focus or validation. |
control | HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement | Underlying form-associated native control. Use focus() for keyboard focus; Select.control is hidden and its focus() method targets the visible trigger. |
update | (patch: Partial<ToggleOptions>) => void | Shallow-merge an options patch into the current configuration. Arrays/adornment objects replace their previous value. User-change callbacks are not emitted. Call before destroy; updates afterward throw. |
getValue | () => boolean | Read the current user value; Boolean for Checkbox/Switch/RadioButton, string for TextInput/TextArea/RadioGroup/Select. Use this after programmatic updates or reset to synchronize your state. |
reset | () => void | Restore the initial Value/Checked (and Checkbox Indeterminate), retaining current options such as labels and choices. Does not emit Change or clear an application Error. A non-canceled form reset also invokes this when mounted inside that form. |
focus | () => void | Focus the visible control. RadioGroup prefers the selected enabled option, then the first enabled option; Select focuses its custom trigger. |
validate | () => boolean | Calls browser reportValidity and returns a Boolean; it may focus the invalid control. RadioGroup checks its enabled inputs. Clear a stale Error first. There is no ValidationChanged callback on these new fields. |
destroy | () => void | Remove owned DOM and listeners. Destroy child component instances before their layout. Safe to call repeatedly; do not use other methods afterward. |
Related data types
Expand a type for its exact fields and allowed values. Pass objects and arrays directly in Web code.
RadioButtonOptions
Current local TypeScript declaration. Use the component-specific options and callbacks shown above.
interface RadioButtonOptions extends FieldOptions { Checked?: boolean; Value: string; }FieldOptions
Common typed field options. FormField only applies presentation and ARIA; see its option notes for properties managed by the consumer.
interface FieldOptions {
Id?: string; Name?: string; Label?: string; Description?: string; Error?: string;
Required?: boolean; Disabled?: boolean; ReadOnly?: boolean; Size?: FieldSize;
ExtendedClass?: string;
}FieldSize
Allowed shared input sizes.
type FieldSize = 'Small' | 'Medium' | 'Large';FieldEvents
Current local TypeScript declaration. Use the component-specific options and callbacks shown above.
interface FieldEvents<T> { Change?: (value: T) => void; Blur?: () => void; }FieldComponent
Current local TypeScript declaration. Use the component-specific options and callbacks shown above.
interface FieldComponent<P, T> {
element: HTMLElement; control: HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement;
update(patch: Partial<P>): void; getValue(): T; reset(): void; focus(): void;
validate(): boolean; destroy(): void;
}ToggleOptions
Internal return-type alias shared by checkbox/switch/radio implementations. For application options, import the component-specific CheckboxOptions, SwitchOptions or RadioButtonOptions.
type ToggleOptions = CheckboxOptions & SwitchOptions;CheckboxOptions
Current local TypeScript declaration. Use the component-specific options and callbacks shown above.
interface CheckboxOptions extends FieldOptions { Checked?: boolean; Indeterminate?: boolean; Value?: string; }SwitchOptions
Current local TypeScript declaration. Use the component-specific options and callbacks shown above.
interface SwitchOptions extends FieldOptions { Checked?: boolean; OnText?: string; OffText?: string; }Verified native contract for BluKavantUi_Community_Inputs → Essentials → RadioButton. Bindings, events and layout were verified in the compiled development consumer on 2026-10-24.
Browser checks cover labels, keyboard interactions, values and cleanup. Scoped Safari VoiceOver and browser checks passed; this is not a full-library conformance certification. Test your composed application with its actual content and assistive technologies.
Purpose and use
A single radio choice for a group that shares a name.
Keyboard design guidance
Use Tab to reach the control. Space toggles choices; radio groups support arrow navigation. Inputs retain standard text-editing shortcuts.
See the support status above for review coverage and any limitations.
In your application
Provide useful labels, preserve visible focus, and test the component with your actual content. Use text alongside status colors and check contrast in each state.
Events0No events yet.
Interact with an example to see its events.