- Radio
- Examples
- Basic Radio
- Checked
- Disabled
- Sizes
- Radio Groups
- Description
- Label and Label Tooltip
- Contained Style
- Horizontal Layout
- Selected Content
- Form Integration
- Required Validation
- Custom Validity
- External Form Association
- Events
- Methods
- Complete Example
- Importing
- Slots
- Properties
- Events
- Methods
- Parts
- Dependencies
Radio
<zn-radio> | ZnRadio
Short summary of the component’s intended use.
<zn-radio>Radio option</zn-radio>
This component works with standard <form> elements. Please refer to the section on
form controls to learn more about form submission and
client-side validation.
Examples
Basic Radio
A basic radio button with a label.
<zn-radio>Default option</zn-radio>
Checked
Use the checked attribute to activate the radio by default.
<zn-radio checked>Selected option</zn-radio>
Disabled
Use the disabled attribute to disable the radio.
<zn-radio disabled>Disabled radio</zn-radio> <br /> <zn-radio disabled checked>Disabled and checked</zn-radio>
Sizes
Use the size attribute to change the radio size. Available sizes are small,
medium (default), and large.
<zn-radio size="small">Small</zn-radio> <br /> <zn-radio size="medium">Medium</zn-radio> <br /> <zn-radio size="large">Large</zn-radio>
Radio Groups
Radio buttons are typically used in groups where only one option can be selected. Radios with the same
name will be mutually exclusive.
<div id="basic-radio-group"> <zn-radio name="color" value="red">Red</zn-radio> <br /> <zn-radio name="color" value="green">Green</zn-radio> <br /> <zn-radio name="color" value="blue" checked>Blue</zn-radio> </div>
Description
Add descriptive help text to radios with the description attribute. For descriptions that
contain HTML, use the description slot instead.
<zn-radio name="plan" description="Best for individuals and small teams">Basic Plan</zn-radio> <br /> <zn-radio name="plan" description="Includes advanced features and priority support">Pro Plan</zn-radio> <br /> <zn-radio name="plan"> Enterprise Plan <div slot="description"> Custom pricing with <strong>dedicated support</strong> and enterprise features. </div> </zn-radio>
Label and Label Tooltip
Use the label attribute to add a form control label above the radio group. Use
label-tooltip to provide additional context.
<zn-radio label="Notification Preferences" label-tooltip="Choose how you want to be notified"> Email notifications </zn-radio> <br /> <zn-radio label="Notification Preferences" label-tooltip="Choose how you want to be notified"> SMS notifications </zn-radio>
Contained Style
Add the contained attribute to draw a card-like container around a radio. This style is useful
for giving more emphasis to radio options.
<zn-radio name="payment" value="credit" description="Pay with Visa, Mastercard, or Amex" contained checked>Credit Card</zn-radio> <br /> <zn-radio name="payment" value="paypal" description="Fast and secure PayPal checkout" contained>PayPal</zn-radio> <br /> <zn-radio name="payment" value="bank" description="Direct bank transfer (3-5 business days)" contained>Bank Transfer</zn-radio>
Horizontal Layout
Use the horizontal attribute to apply styles relevant to radios in a horizontal layout.
<div style="display: flex; gap: 1rem;"> <zn-radio name="size" horizontal>Small</zn-radio> <zn-radio name="size" horizontal checked>Medium</zn-radio> <zn-radio name="size" horizontal>Large</zn-radio> </div>
Selected Content
Use the selected-content slot to display additional content (such as an input field) inside a
contained radio when it is checked. The slot is unstyled by default. Use
::part(selected-content) to style the content as needed.
Note: This feature only works with the contained style. The
selected-content slot cannot be used for radios rendered with ts_form_for.
Estimated delivery: 5–7 business days
Estimated delivery: 1–2 business days
<zn-radio name="shipping" value="standard" contained checked> Standard Shipping <div slot="selected-content"> <p>Estimated delivery: 5-7 business days</p> </div> </zn-radio> <br /> <zn-radio name="shipping" value="express" contained> Express Shipping <div slot="selected-content"> <p>Estimated delivery: 1-2 business days</p> <zn-input style="width: 280px;" label="Delivery instructions" placeholder="e.g., Leave at door"></zn-input> </div> </zn-radio> <style> zn-radio::part(selected-content) { font-size: 14px; font-weight: normal; color: #6D7176; margin-top: 1rem; } </style>
Form Integration
Radios work seamlessly with forms and will be submitted with form data. Only the selected radio’s value will be submitted.
<form id="radio-form"> <div style="margin-bottom: 1rem;"> <strong>Choose your plan:</strong> <br /><br /> <zn-radio name="subscription" value="free">Free Plan</zn-radio> <br /> <zn-radio name="subscription" value="pro" checked>Pro Plan - $9.99/mo</zn-radio> <br /> <zn-radio name="subscription" value="enterprise">Enterprise Plan - Contact us</zn-radio> </div> <zn-button type="submit" color="primary">Submit</zn-button> <zn-button type="reset" color="secondary">Reset</zn-button> </form> <script type="module"> const form = document.querySelector('#radio-form'); form.addEventListener('submit', (event) => { event.preventDefault(); const formData = new FormData(form); const data = Object.fromEntries(formData.entries()); alert('Form submitted: ' + JSON.stringify(data, null, 2)); }); </script>
Required Validation
Use the required attribute to make the radio required. The form will not submit unless one of
the radios in the group is selected.
<form id="required-form"> <strong>Select your preferred contact method:</strong> <br /><br /> <zn-radio name="contact" value="email" required>Email</zn-radio> <br /> <zn-radio name="contact" value="phone" required>Phone</zn-radio> <br /> <zn-radio name="contact" value="mail" required>Mail</zn-radio> <br /><br /> <zn-button type="submit" color="primary">Submit</zn-button> </form> <script type="module"> const form = document.querySelector('#required-form'); form.addEventListener('submit', (event) => { event.preventDefault(); alert('Form is valid!'); }); </script>
Custom Validity
Use the setCustomValidity() method to set a custom validation message. This will prevent the
form from submitting and make the browser display the error message you provide. To clear the error, call
this function with an empty string.
<form class="custom-validity"> <strong>Accept terms:</strong> <br /><br /> <zn-radio name="terms" value="accept">I accept the terms</zn-radio> <br /> <zn-radio name="terms" value="decline">I decline</zn-radio> <br /><br /> <zn-button type="submit" color="primary">Submit</zn-button> </form> <script type="module"> const form = document.querySelector('.custom-validity'); const radios = form.querySelectorAll('zn-radio'); const errorMessage = 'You must accept the terms to continue'; // Set initial validity customElements.whenDefined('zn-radio').then(async () => { await Promise.all(Array.from(radios).map(r => r.updateComplete)); radios[0].setCustomValidity(errorMessage); }); // Update validity on change radios.forEach(radio => { radio.addEventListener('zn-change', () => { if (radio.value === 'accept' && radio.checked) { radios.forEach(r => r.setCustomValidity('')); } else if (radio.value === 'decline' && radio.checked) { radios.forEach(r => r.setCustomValidity(errorMessage)); } }); }); // Wait for controls to be defined before attaching form listeners await Promise.all([ customElements.whenDefined('zn-radio') ]).then(() => { form.addEventListener('submit', event => { event.preventDefault(); alert('All fields are valid!'); }); }); </script>
External Form Association
Use the form attribute to associate the radio with a form element by ID, even if the radio is
not a descendant of the form.
Choose an option:
<form id="external-form"> <zn-button type="submit" color="primary">Submit External Form</zn-button> </form> <br /><br /> <strong>Choose an option:</strong> <br /><br /> <zn-radio form="external-form" name="external-option" value="option1" checked>Option 1</zn-radio> <br /> <zn-radio form="external-form" name="external-option" value="option2">Option 2</zn-radio> <script type="module"> const form = document.querySelector('#external-form'); form.addEventListener('submit', (event) => { event.preventDefault(); const formData = new FormData(form); alert('Selected: ' + formData.get('external-option')); }); </script>
Events
Radios emit several events that you can listen to:
zn-change- Emitted when the checked state changeszn-input- Emitted when the radio receives inputzn-focus- Emitted when the radio gains focuszn-blur- Emitted when the radio loses focuszn-invalid- Emitted when form validation fails
<div> <strong>Try interacting with the radios:</strong> <br /><br /> <zn-radio class="event-radio" name="event-demo" value="option1" checked>Option 1</zn-radio> <br /> <zn-radio class="event-radio" name="event-demo" value="option2">Option 2</zn-radio> <br /> <zn-radio class="event-radio" name="event-demo" value="option3">Option 3</zn-radio> <div id="event-output" style="margin-top: 1rem; padding: 1rem; background: #f5f5f5; border-radius: 4px;"> <strong>Events:</strong> <ul id="event-list" style="margin: 0.5rem 0 0 0; padding-left: 1.5rem;"></ul> </div> </div> <script type="module"> const radios = document.querySelectorAll('.event-radio'); const eventList = document.querySelector('#event-list'); function logEvent(eventName, detail = '') { const li = document.createElement('li'); li.textContent = `${eventName}${detail ? ': ' + detail : ''}`; eventList.insertBefore(li, eventList.firstChild); // Keep only last 5 events while (eventList.children.length > 5) { eventList.removeChild(eventList.lastChild); } } radios.forEach(radio => { radio.addEventListener('zn-change', (e) => { logEvent('zn-change', `${e.target.value} selected`); }); radio.addEventListener('zn-input', () => { logEvent('zn-input'); }); radio.addEventListener('zn-focus', (e) => { logEvent('zn-focus', e.target.value); }); radio.addEventListener('zn-blur', (e) => { logEvent('zn-blur', e.target.value); }); }); </script>
Methods
Radios provide several methods for programmatic control:
click()- Simulates a click on the radiofocus()- Sets focus on the radioblur()- Removes focus from the radiocheckValidity()- Checks validity without showing a messagereportValidity()- Checks validity and shows the browser’s validation messagesetCustomValidity(message)- Sets a custom validation messagegetForm()- Gets the associated form, if one exists
<div> <zn-radio id="method-radio-1" name="method-demo" checked>Option 1</zn-radio> <br /> <zn-radio id="method-radio-2" name="method-demo">Option 2</zn-radio> <br /> <zn-radio id="method-radio-3" name="method-demo">Option 3</zn-radio> <br /><br /> <zn-button id="click-btn" size="small">Click Option 2</zn-button> <zn-button id="focus-btn" size="small" color="info">Focus Option 3</zn-button> <zn-button id="blur-btn" size="small" color="secondary">Blur All</zn-button> <zn-button id="validate-btn" size="small" color="warning">Check Validity</zn-button> </div> <script type="module"> const radio1 = document.querySelector('#method-radio-1'); const radio2 = document.querySelector('#method-radio-2'); const radio3 = document.querySelector('#method-radio-3'); document.querySelector('#click-btn').addEventListener('click', () => { radio2.click(); }); document.querySelector('#focus-btn').addEventListener('click', () => { radio3.focus(); }); document.querySelector('#blur-btn').addEventListener('click', () => { document.activeElement?.blur(); }); document.querySelector('#validate-btn').addEventListener('click', () => { const isValid = radio1.checkValidity(); alert('Radio group is ' + (isValid ? 'valid' : 'invalid')); }); </script>
Complete Example
Here’s a comprehensive example showing a radio group with contained style, descriptions, and selected content:
<form id="complete-example"> <div style="max-width: 600px;"> <h3 style="margin-top: 0;">Choose Your Subscription</h3> <zn-radio name="plan" value="starter" description="Perfect for getting started with basic features" contained> Starter Plan - Free <div slot="selected-content"> <p>Includes:</p> <ul style="margin: 0.5rem 0; padding-left: 1.5rem;"> <li>Up to 3 users</li> <li>5 GB storage</li> <li>Community support</li> </ul> </div> </zn-radio> <br /> <zn-radio name="plan" value="professional" description="Advanced features for growing teams" contained checked> Professional Plan - $29/month <div slot="selected-content"> <p>Includes everything in Starter, plus:</p> <ul style="margin: 0.5rem 0; padding-left: 1.5rem;"> <li>Up to 25 users</li> <li>100 GB storage</li> <li>Priority email support</li> <li>Advanced analytics</li> </ul> </div> </zn-radio> <br /> <zn-radio name="plan" value="enterprise" description="Custom solutions for large organizations" contained> Enterprise Plan - Custom pricing <div slot="selected-content"> <p>Includes everything in Professional, plus:</p> <ul style="margin: 0.5rem 0; padding-left: 1.5rem;"> <li>Unlimited users</li> <li>Unlimited storage</li> <li>24/7 phone support</li> <li>Custom integrations</li> <li>Dedicated account manager</li> </ul> <zn-input style="width: 100%; margin-top: 1rem;" label="Company name" placeholder="Enter your company name" required> </zn-input> </div> </zn-radio> <br /><br /> <zn-button type="submit" color="success" style="margin-right: 0.5rem;">Continue</zn-button> <zn-button type="reset" color="secondary">Reset</zn-button> </div> </form> <style> zn-radio::part(selected-content) { font-size: 14px; font-weight: normal; color: #6D7176; margin-top: 1rem; } zn-radio::part(selected-content) p { margin: 0 0 0.5rem 0; font-weight: 500; } </style> <script type="module"> const form = document.querySelector('#complete-example'); form.addEventListener('submit', (event) => { event.preventDefault(); const formData = new FormData(form); const plan = formData.get('plan'); const company = formData.get('company') || 'N/A'; alert(`Selected: ${plan}\nCompany: ${company}`); }); </script>
Importing
If you’re using the autoloader or the traditional loader, you can ignore this section. Otherwise, feel free to use any of the following snippets to cherry pick this component.
To import this component from the CDN using a script tag:
<script type="module" src="https://cdn.jsdelivr.net/npm/@kubex/zinc@1.0.86/dist/components/radio/radio.js"></script>
To import this component from the CDN using a JavaScript import:
import 'https://cdn.jsdelivr.net/npm/@kubex/zinc@1.0.86/dist/components/radio/radio.js';
To import this component using a bundler:
import '@kubex/zinc/dist/components/radio/radio.js';
Slots
| Name | Description |
|---|---|
| (default) | The radio’s label. |
description
|
A description of the radio’s label. Serves as help text for a radio item. Alternatively, you can use
the description attribute.
|
selected-content
|
Use to nest rich content (like an input) inside a selected radio item. Use only with the contained style. |
Learn more about using slots.
Properties
| Name | Description | Reflects | Type | Default |
|---|---|---|---|---|
name
|
The name of the radio, submitted as a name/value pair with form data. |
string
|
''
|
|
value
|
The current value of the radio, submitted as a name/value pair with form data. |
string
|
- | |
size
|
The radio’s size. |
|
'small' | 'medium' | 'large'
|
'medium'
|
disabled
|
Disables the radio. |
|
boolean
|
false
|
checked
|
Draws the radio in a checked state. |
|
boolean
|
false
|
contained
|
Draws a container around the radio. |
|
boolean
|
false
|
horizontal
|
Applies styles relevant to radios in a horizontal layout. |
|
boolean
|
false
|
defaultChecked
|
The default value of the form control. Primarily used for resetting the form control. |
boolean
|
false
|
|
form
|
By default, form controls are associated with the nearest containing
<form> element. This attribute allows you to place the form control outside a
form and associate it with the form that has this id. The form must be in the same
document or shadow root for this to work.
|
|
string
|
''
|
required
|
Makes the radio a required field. |
|
boolean
|
false
|
description
|
The radio’s help text. If you need to display HTML, use the description slot instead.
|
string
|
''
|
|
validity
|
Gets the validity state object | - | - | |
validationMessage
|
Gets the validation message | - | - | |
updateComplete |
A read-only promise that resolves when the component has finished updating. |
Learn more about attributes and properties.
Events
| Name | React Event | Description | Event Detail |
|---|---|---|---|
zn-blur |
|
Emitted when the radio loses focus. | - |
zn-change |
|
Emitted when the checked state changes. | - |
zn-focus |
|
Emitted when the radio gains focus. | - |
zn-input |
|
Emitted when the radio receives input. | - |
zn-invalid |
|
Emitted when the form control has been checked for validity and its constraints aren’t satisfied. | - |
Learn more about events.
Methods
| Name | Description | Arguments |
|---|---|---|
click() |
Simulates a click on the radio. | - |
focus() |
Sets focus on the radio. |
options: FocusOptions
|
blur() |
Removes focus from the radio. | - |
checkValidity() |
Checks for validity but does not show a validation message. Returns true when valid and
false when invalid.
|
- |
getForm() |
Gets the associated form, if one exists. | - |
reportValidity() |
Checks for validity and shows the browser’s validation message if the control is invalid. | - |
setCustomValidity() |
Sets a custom validation message. The value provided will be shown to the user when the form is submitted. To clear the custom validation message, call this method with an empty string. |
message: string
|
Learn more about methods.
Parts
| Name | Description |
|---|---|
base |
The component’s base wrapper. |
control |
The square container that wraps the radio’s checked state. |
control--checked |
Matches the control part when the radio is checked. |
checked-icon |
The checked icon, an <zn-icon> element. |
label |
The container that wraps the radio’s label. |
description |
The container that wraps the radio’s description. |
selected-content |
The container that wraps optional content that appears when a radio is checked. |
Learn more about customizing CSS parts.
Dependencies
This component automatically imports the following dependencies.
<zn-example><zn-icon>