Skip to main content
Since Shoelace 2.0 Code stable Pattern stable Figma ready

Radio

sl-radio

Shoelace’s Radio component, more commonly called Radio Button, allows the user to select a single option from a group. Radios should always be nested within a Radio Group.

Examples

Basic Radio

Radios are designed to be used with radio groups.

Issue shares Employee buyback Cancel a certificate
<sl-radio-group label="What would you like to do?" name="a" value="issue_shares" required>
  <sl-radio value="issue_shares">Issue shares</sl-radio>
  <sl-radio value="employee_buyback">Employee buyback</sl-radio>
  <sl-radio value="cancel_certificate">Cancel a certificate</sl-radio>
</sl-radio-group>
sl-radio-group[
  label="What would you like to do?"
  name="a"
  value="issue_shares"
  required
]
  sl-radio value="issue_shares" Issue shares
  sl-radio value="employee_buyback" Employee buyback
  sl-radio value="cancel_certificate" Cancel a certificate
/*
  — NOTE: To set default value for initial page load, ensure a value is set
  in the controller's #new action:
  e.g. if using `ts_form_for @cap_table_event`, set @cap_table_event = CapTableEvent.new(a: "issue_shares")
*/
= ts_form_for ... do |f|
  = f.input :a,
    as: :radio_buttons,
    label: "What would you like to do?",
    collection: [
      ["Issue shares", "issue_shares"],
      ["Employee buyback", "employee_buyback"],
      ["Cancel a certificate", "cancel_certificate"],
    ],
    wrapper_html: {
      required: true
    }
import SlRadio from '@teamshares/shoelace/dist/react/radio';
import SlRadioGroup from '@teamshares/shoelace/dist/react/radio-group';

const App = () => (
  <SlRadioGroup label="Select an option" name="a" value="1">
    <SlRadio value="1">Option 1</SlRadio>
    <SlRadio value="2">Option 2</SlRadio>
    <SlRadio value="3">Option 3</SlRadio>
  </SlRadioGroup>
);

Description

Add descriptive help text to individual radio items with the description attribute. For descriptions that contain HTML, use the description slot instead.

Issue shares Employee buyback Cancel a certificate
Declares certificate to be null and void
<sl-radio-group label="What would you like to do?" name="a" value="issue_shares">
  <sl-radio value="issue_shares" description="Awards company shares to an employee">Issue shares</sl-radio>
  <sl-radio value="employee_buyback" description="Buys back vested shares from departing employee owners">Employee buyback</sl-radio>
  <sl-radio value="cancel_certificate">Cancel a certificate
    <div slot="description">Declares certificate to be <em>null and void</em></div>
  </sl-radio>
</sl-radio-group>
sl-radio-group[
  label="What would you like to do?"
  name="a"
  value="issue_shares"
]
  sl-radio[
    value="issue_shares"
    description="Awards company shares to an employee"
  ]
    | Issue shares
  sl-radio[
    value="employee_buyback"
    description="Buys back vested shares from departing employee owners"
   ]
    | Employee buyback
  sl-radio[
    value="cancel_certificate"
  ]
    | Cancel a certificate
    div slot="description" Declares certificate to be
      em null and void
/*
  — NOTE: To set default value for initial page load, ensure a value is set
  in the controller's #new action:
  e.g. if using `ts_form_for @cap_table_event`,
  set @cap_table_event = CapTableEvent.new(a: "issue_shares")

  — NOTE: Slots are not supported with ts_form_for —
  — Example below shows usage of "description" as attribute —

  When rendering `sl-radio-group` with ts_form_for, pass additional
  attributes such as `disabled` and `description` as extra items
  in the collection array after the label and value.
  By default Simple Form will use the first item
  as the label and the second item as the value, then pass
  any additional array items as attributes on the `sl-radio`.
*/
= ts_form_for ... do |f|
  = f.input :a,
    as: :radio_buttons,
    label: "What would you like to do?",
    collection: [
      [
        "Issue shares",
        "issue_shares",
        description: "Awards company shares to an employee",
      ],
      [
        "Employee buyback",
        "employee_buyback",
        description: "Buys back vested shares from departing employee owners",
      ],
      [
        "Cancel a certificate",
        "cancel_certificate",
        description: "Declares certificate to be null and void",
      ],
    ],
    wrapper_html: {
      required: true
    }
import SlRadio from '@teamshares/shoelace/dist/react/radio';
import SlRadioGroup from '@teamshares/shoelace/dist/react/radio-group';

const App = () => (
  <SlRadioGroup label="Select an option" name="a" value="1">
    <SlRadio value="1">Option 1</SlRadio>
    <SlRadio value="2">Option 2</SlRadio>
    <SlRadio value="3">Option 3</SlRadio>
  </SlRadioGroup>
);

Contained

Add the contained attribute to the Radio Group to draw a card-like container around each radio item in the radio group. This style is useful for giving more emphasis to the list of options.

Issue shares Employee buyback Cancel a certificate
Declares certificate to be null and void
<sl-radio-group label="What would you like to do?" name="a" value="issue_shares" contained>
  <sl-radio value="issue_shares" description="Awards company shares to an employee">Issue shares</sl-radio>
  <sl-radio value="employee_buyback" description="Buys back vested shares from departing employee owners">Employee buyback</sl-radio>
  <sl-radio value="cancel_certificate" disabled>Cancel a certificate
    <div slot="description">Declares certificate to be <em>null and void</em></div>
  </sl-radio>
</sl-radio-group>
sl-radio-group[
  label="What would you like to do?"
  name="a"
  value="issue_shares"
  contained=true
]
  sl-radio[
    value="issue_shares"
    description="Awards company shares to an employee"
  ]
    | Issue shares
  sl-radio[
    value="employee_buyback"
    description="Buys back vested shares from departing employee owners"
   ]
    | Employee buyback
  sl-radio[
    value="cancel_certificate"
    disabled=true
  ]
    | Cancel a certificate
    div slot="description" Declares certificate to be
      em null and void
/*
  — NOTE: To set default value for initial page load, ensure a value is set
  in the controller's #new action:
  e.g. if using `ts_form_for @cap_table_event`,
  set @cap_table_event = CapTableEvent.new(a: "issue_shares")

  — NOTE: Slots are not supported with ts_form_for —
  — Example below shows usage of "description" as attribute —

  When rendering `sl-radio-group` with ts_form_for, pass additional
  attributes such as `disabled` and `description` as extra items
  in the collection array after the label and value.
  By default Simple Form will use the first item
  as the label and the second item as the value, then pass
  any additional array items as attributes on the `sl-radio`.
*/
= ts_form_for ... do |f|
  = f.input :a,
    as: :radio_buttons,
    label: "What would you like to do?",
    collection: [
      [
        "Issue shares",
        "issue_shares",
        description: "Awards company shares to an employee",
      ],
      [
        "Employee buyback",
        "employee_buyback",
        description: "Buys back vested shares from departing employee owners",
      ],
      [
        "Cancel a certificate",
        "cancel_certificate",
        description: "Declares certificate to be null and void",
        disabled: true,
      ]
    ],
    wrapper_html: {
      contained: true
    }
import { SlRadio } from '@teamshares/shoelace/dist/react';

const App = () => (
  <>
    <SlRadioGroup label="Select an option" name="a" value="3">
      <SlRadio contained value="1">
        Option 1
      </SlRadio>
      <SlRadio contained value="2" disabled>
        Option 2
      </SlRadio>
      <SlRadio contained value="3">
        Option 3<div slot="description">A short description about this option</div>
      </SlRadio>
    </SlRadioGroup>
  </>
);

Selected Content

Use the selected-content slot to display additional content (such as an input field) inside a contained radio when the radio is selected (checked). The slot is unstyled by default. Use ::part(selected-content) to style the content as needed.

Last statement balance
This is the amount you owe as of your Feb 21 statement
Current balance
This is the amount you owe as of today
Custom amount
<sl-radio-group label="Select your payment amount" name="a" value="statement-balance" contained>
  <sl-radio value="statement-balance" description="$10.00">Last statement balance
    <div slot="selected-content">This is the amount you owe as of your Feb 21 statement</div>
  </sl-radio>
  <sl-radio value="current-balance" description="$150.00">Current balance
    <div slot="selected-content">This is the amount you owe as of today</div>
  </sl-radio>
  <sl-radio value="custom">
    Custom amount
    <sl-input style="width: 240px;" slot="selected-content" label="Amount" type="currency">
  </sl-radio>
</sl-radio-group>

<style>
  sl-radio::part(selected-content) {
    font-size: 14px;
    font-weight: normal;
    color: #6D7176;
  }
</style>
sl-radio-group[
  label="Select your payment amount"
  name="a"
  value="statement-balance"
  contained=true
]
  sl-radio[
    value="statement-balance"
    description="$10.00"
  ]
    | Last statement balance
    div slot="selected-content" This is the amount you owe as of your Feb 21 statement
  sl-radio[
    value="current-balance"
    description="$150.00"
  ]
    | Current balance
    div slot="selected-content" This is the amount you owe as of today
  sl-radio[
    value="custom"
  ]
    | Custom amount
    sl-input[
      style="width: 240px;"
      slot="selected-content"
      label="Amount"
      type="currency"
    ]

css:
  sl-radio::part(selected-content) {
    font-size: 14px;
    font-weight: normal;
    color: #6D7176;
  }
/*
  NOTE: `ts_form_for` doesn't support slots. The `selected-content` slot
  cannot be used for radio groups rendered with `ts_form_for`.
*/
import { SlRadio } from '@teamshares/shoelace/dist/react';

const App = () => (
  <>
    <SlRadioGroup label="Select an option" name="a" value="3">
      <SlRadio contained value="1">
        Option 1
      </SlRadio>
      <SlRadio contained value="2" disabled>
        Option 2
      </SlRadio>
      <SlRadio contained value="3">
        Option 3<div slot="description">A short description about this option</div>
      </SlRadio>
    </SlRadioGroup>
  </>
);

Initial Value

To set the initial value and checked state, use the value attribute on the containing radio group. Generally a radio group should have one item selected by default.

Issue shares Employee buyback Cancel a certificate
<sl-radio-group label="What would you like to do?" name="a" value="issue_shares">
  <sl-radio value="issue_shares">Issue shares</sl-radio>
  <sl-radio value="employee_buyback">Employee buyback</sl-radio>
  <sl-radio value="cancel_certificate">Cancel a certificate</sl-radio>
</sl-radio-group>
sl-radio-group[
  label="What would you like to do?"
  name="a"
  value="issue_shares"
]
  sl-radio value="issue_shares" Issue shares
  sl-radio value="employee_buyback" Employee buyback
  sl-radio value="cancel_certificate" Cancel a certificate
/*
  — NOTE: To set default value for initial page load, ensure a value is set
  in the controller's #new action:
  e.g. if using `ts_form_for @cap_table_event`, set @cap_table_event = CapTableEvent.new(a: "issue_shares")
*/
= ts_form_for ... do |f|
  = f.input :a,
    as: :radio_buttons,
    label: "What would you like to do?",
    collection: [
      ["Issue shares", "issue_shares"],
      ["Employee buyback", "employee_buyback"],
      ["Cancel a certificate", "cancel_certificate"],
    ]
import SlRadio from '@teamshares/shoelace/dist/react/radio';
import SlRadioGroup from '@teamshares/shoelace/dist/react/radio-group';

const App = () => (
  <SlRadioGroup label="Select an option" name="a" value="3">
    <SlRadio value="1">Option 1</SlRadio>
    <SlRadio value="2">Option 2</SlRadio>
    <SlRadio value="3">Option 3</SlRadio>
  </SlRadioGroup>
);

Disabled

Use the disabled attribute to disable a radio.

Issue shares Employee buyback Cancel a certificate
<sl-radio-group label="What would you like to do?" name="a" value="issue_shares">
  <sl-radio value="issue_shares">Issue shares</sl-radio>
  <sl-radio value="employee_buyback">Employee buyback</sl-radio>
  <sl-radio value="cancel_certificate" disabled>Cancel a certificate</sl-radio>
</sl-radio-group>
sl-radio-group[
  label="What would you like to do?"
  name="a"
  value="issue_shares"
]
  sl-radio value="issue_shares" Issue shares
  sl-radio value="employee_buyback" Employee buyback
  sl-radio value="cancel_certificate" disabled=true Cancel a certificate
/*
  — NOTE: To set default value for initial page load, ensure a value is set
  in the controller's #new action:
  e.g. if using `ts_form_for @cap_table_event`,
  set @cap_table_event = CapTableEvent.new(a: "issue_shares")

  When rendering `sl-radio-group` with ts_form_for, pass additional
  attributes such as `disabled` and `description` as extra items
  in the collection array after the label and value.
  By default Simple Form will use the first item
  as the label and the second item as the value, then pass
  any additional array items as attributes on the `sl-radio`.
*/

= ts_form_for ... do |f|
  = f.input :a,
    as: :radio_buttons,
    label: "What would you like to do?",
    collection: [
      [
        "Issue shares",
        "issue_shares",
      ],
      [
        "Employee buyback",
        "employee_buyback",
      ],
      [
        "Cancel a certificate",
        "cancel_certificate",
        disabled: true,
      ],
    ]
import SlRadio from '@teamshares/shoelace/dist/react/radio';
import SlRadioGroup from '@teamshares/shoelace/dist/react/radio-group';

const App = () => (
  <SlRadioGroup label="Select an option" name="a" value="1">
    <SlRadio value="1">Option 1</SlRadio>
    <SlRadio value="2" disabled>
      Option 2
    </SlRadio>
    <SlRadio value="3">Option 3</SlRadio>
  </SlRadioGroup>
);

Usage

Testing

With Cypress

Component Props

Property Default Details
value

string

The radio’s value. When selected, the radio group will receive this value.

size 'medium'

'small' | 'medium' | 'large'

The radio’s size. When used inside a radio group, the size will be determined by the radio group’s size so this attribute can typically be omitted.

description ''

string

A description of the radio’s label. Serves as help text for individual radio items. If you need to display HTML, use the description slot instead.

disabled false

boolean

Disables the radio.

contained false

boolean

Draws a container around the radio.

horizontal false

boolean

Applies styles relevant to radios in a horizontal layout.

updateComplete A read-only promise that resolves when the component has finished updating.

Learn more about attributes and properties.

Slots

Name Details
(default) The radio’s label.
description A description of the radio’s label. Serves as help text for individual radio items. 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.

Events

Name Name Name React Event Details
sl-blur sl-blur sl-blur onSlBlur

Emitted when the control loses focus.

sl-focus sl-focus sl-focus onSlFocus

Emitted when the control gains focus.

Learn more about events.

CSS Parts

Name Description
base The component’s base wrapper.
control The circular container that wraps the radio’s checked state.
control--checked The radio control when the radio is checked.
checked-icon The checked icon, an <sl-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 selected (checked).

Learn more about customizing CSS parts.

Dependencies

This component automatically imports the following dependencies.

  • <sl-icon>