Radio input for mutually exclusive choices.
Introduction
Use radios when users must pick exactly one option from a short list. Group options by sharing the same name. For yes/no toggles that take effect immediately, Switch may be clearer; for multiple selections, use Checkbox.
Each Radio includes built-in label chrome. Arrow keys move selection within a native radio group in the browser.
Import
import { Radio } from "@bridge-ui/vue/Components/Radio";import { Radio } from "@bridge-ui/react/Components/Radio";Basic usage
Render multiple Radio components with the same name and distinct value props. In React, use checked and onChange for controlled state; in Vue, bind the same v-model to each radio in the group. For an initial selection without binding, use defaultChecked in React or default-checked in Vue.
<script setup lang="ts">
import { ref } from "vue";
import { Radio } from "@bridge-ui/vue/Components/Radio";
const plan = ref("starter");
</script>
<template>
<div class="flex w-full flex-col gap-6">
<Radio
v-model="plan"
name="plan-vue"
value="starter"
end-label="Starter"
description="Free tier for individuals."
/>
<Radio
value="pro"
v-model="plan"
name="plan-vue"
end-label="Pro"
description="For growing teams."
/>
</div>
</template>
import { useState } from "react";
import { Radio } from "@bridge-ui/react/Components/Radio";
export default function RadioBasic() {
const [plan, setPlan] = useState("starter");
return (
<div className="flex w-full flex-col gap-6">
<Radio
value="starter"
name="plan-react"
endLabel="Starter"
checked={plan === "starter"}
onChange={() => setPlan("starter")}
description="Free tier for individuals."
/>
<Radio
value="pro"
endLabel="Pro"
name="plan-react"
checked={plan === "pro"}
onChange={() => setPlan("pro")}
description="For growing teams."
/>
</div>
);
}
Colors
Use the color prop to change the radio color. Available colors: primary, secondary, success, info, warning, error, and dark.
<script setup lang="ts">
import { ref } from "vue";
import { Radio } from "@bridge-ui/vue/Components/Radio";
const selected = ref("primary");
</script>
<template>
<div class="flex w-full flex-col gap-6">
<Radio
color="primary"
value="primary"
name="colors-vue"
v-model="selected"
end-label="primary radio"
/>
<Radio
name="colors-vue"
color="secondary"
value="secondary"
v-model="selected"
end-label="secondary radio"
/>
<Radio
color="success"
value="success"
name="colors-vue"
v-model="selected"
end-label="success radio"
/>
<Radio
color="info"
value="info"
name="colors-vue"
v-model="selected"
end-label="info radio"
/>
<Radio
color="warning"
value="warning"
name="colors-vue"
v-model="selected"
end-label="warning radio"
/>
<Radio
color="error"
value="error"
name="colors-vue"
v-model="selected"
end-label="error radio"
/>
<Radio
color="dark"
value="dark"
name="colors-vue"
v-model="selected"
end-label="dark radio"
/>
</div>
</template>
import { useState } from "react";
import { Radio } from "@bridge-ui/react/Components/Radio";
export default function RadioColors() {
const [color, setColor] = useState("primary");
return (
<div className="flex w-full flex-col gap-6">
<Radio
color="primary"
value="primary"
name="colors-react"
endLabel="primary radio"
checked={color === "primary"}
onChange={() => setColor("primary")}
/>
<Radio
color="secondary"
value="secondary"
name="colors-react"
endLabel="secondary radio"
checked={color === "secondary"}
onChange={() => setColor("secondary")}
/>
<Radio
color="success"
value="success"
name="colors-react"
endLabel="success radio"
checked={color === "success"}
onChange={() => setColor("success")}
/>
<Radio
color="info"
value="info"
name="colors-react"
endLabel="info radio"
checked={color === "info"}
onChange={() => setColor("info")}
/>
<Radio
color="warning"
value="warning"
name="colors-react"
endLabel="warning radio"
checked={color === "warning"}
onChange={() => setColor("warning")}
/>
<Radio
color="error"
value="error"
name="colors-react"
endLabel="error radio"
checked={color === "error"}
onChange={() => setColor("error")}
/>
<Radio
color="dark"
value="dark"
name="colors-react"
endLabel="dark radio"
checked={color === "dark"}
onChange={() => setColor("dark")}
/>
</div>
);
}
Sizes
Control the radio size with the size prop. Available sizes: 2xs, xs, sm, md (default), lg, xl, and 2xl.
<script setup lang="ts">
import { Radio } from "@bridge-ui/vue/Components/Radio";
</script>
<template>
<div class="flex w-full flex-col gap-4">
<Radio
size="2xs"
value="2xs"
default-checked
name="size-2xs-vue"
end-label="2xs radio"
/>
<Radio
size="xs"
value="xs"
default-checked
name="size-xs-vue"
end-label="xs radio"
/>
<Radio
size="sm"
value="sm"
default-checked
name="size-sm-vue"
end-label="sm radio"
/>
<Radio
size="md"
value="md"
default-checked
name="size-md-vue"
end-label="md radio"
/>
<Radio
size="lg"
value="lg"
default-checked
name="size-lg-vue"
end-label="lg radio"
/>
<Radio
size="xl"
value="xl"
default-checked
name="size-xl-vue"
end-label="xl radio"
/>
<Radio
size="2xl"
value="2xl"
default-checked
name="size-2xl-vue"
end-label="2xl radio"
/>
</div>
</template>
import { Radio } from "@bridge-ui/react/Components/Radio";
export default function RadioSizes() {
return (
<div className="flex w-full flex-col gap-4">
<Radio
size="2xs"
value="2xs"
defaultChecked
endLabel="2xs radio"
name="size-2xs-react"
/>
<Radio
size="xs"
value="xs"
defaultChecked
endLabel="xs radio"
name="size-xs-react"
/>
<Radio
size="sm"
value="sm"
defaultChecked
endLabel="sm radio"
name="size-sm-react"
/>
<Radio
size="md"
value="md"
defaultChecked
endLabel="md radio"
name="size-md-react"
/>
<Radio
size="lg"
value="lg"
defaultChecked
endLabel="lg radio"
name="size-lg-react"
/>
<Radio
size="xl"
value="xl"
defaultChecked
endLabel="xl radio"
name="size-xl-react"
/>
<Radio
size="2xl"
value="2xl"
defaultChecked
endLabel="2xl radio"
name="size-2xl-react"
/>
</div>
);
}
Rounded
Use the rounded prop to control border radius. Available values: none, xs, sm, md, lg, xl, 2xl, 3xl, 4xl, and full (defaults vary by component).
<script setup lang="ts">
import { Radio } from "@bridge-ui/vue/Components/Radio";
</script>
<template>
<div class="flex flex-wrap items-center gap-6">
<Radio
value="none"
rounded="none"
default-checked
end-label="none"
name="rounded-none-vue"
/>
<Radio
value="sm"
rounded="sm"
end-label="sm"
default-checked
name="rounded-sm-vue"
/>
<Radio
value="md"
rounded="md"
end-label="md"
default-checked
name="rounded-md-vue"
/>
<Radio
value="2xl"
rounded="2xl"
default-checked
end-label="2xl"
name="rounded-2xl-vue"
/>
<Radio
value="full"
rounded="full"
default-checked
end-label="full"
name="rounded-full-vue"
/>
</div>
</template>
import { Radio } from "@bridge-ui/react/Components/Radio";
export default function RadioRounded() {
return (
<div className="flex flex-wrap items-center gap-6">
<Radio
value="none"
defaultChecked
rounded="none"
endLabel="none"
name="rounded-none-react"
/>
<Radio
value="sm"
rounded="sm"
endLabel="sm"
defaultChecked
name="rounded-sm-react"
/>
<Radio
value="md"
rounded="md"
endLabel="md"
defaultChecked
name="rounded-md-react"
/>
<Radio
value="2xl"
rounded="2xl"
defaultChecked
endLabel="2xl"
name="rounded-2xl-react"
/>
<Radio
value="full"
defaultChecked
rounded="full"
endLabel="full"
name="rounded-full-react"
/>
</div>
);
}
Validation
Use required to mark the field as required, error with errorMessage for invalid state, and disabled to prevent interaction.
<script setup lang="ts">
import { Radio } from "@bridge-ui/vue/Components/Radio";
</script>
<template>
<div class="flex w-full flex-col gap-6">
<Radio
required
value="req"
name="required-vue"
end-label="Required field"
/>
<Radio
error
value="err"
name="error-vue"
end-label="Invalid option"
error-message="Please select a valid option."
/>
<Radio disabled value="off" name="disabled-vue" end-label="Disabled" />
</div>
</template>
import { Radio } from "@bridge-ui/react/Components/Radio";
export default function RadioValidation() {
return (
<div className="flex w-full flex-col gap-6">
<Radio
required
value="req"
name="required-react"
endLabel="Required field"
/>
<Radio
error
value="err"
name="error-react"
endLabel="Invalid option"
errorMessage="Please select a valid option."
/>
<Radio disabled value="off" endLabel="Disabled" name="disabled-react" />
</div>
);
}
Related components
Accessibility
- Arrow keys move selection within a group that shares the same name
- Space selects the focused radio
- A visually hidden native <input type="radio"> holds state; the styled control has aria-hidden
- endLabel is associated with the input through matching id and htmlFor
- error sets aria-invalid on the input and data-invalid on the FormControl root
- disabled sets aria-disabled on the FormControl root
Anatomy
<div data-invalid>
<div>
<!-- row -->
<label>
<input type="radio" class="sr-only" name="group" value="a" />
<span aria-hidden="true">
<span />
<!-- dot when checked -->
</span>
</label>
<label for="...">Option A</label>
</div>
<!-- repeat for each option -->
<p>Description</p>
<p aria-hidden>Error message</p>
</div>API
| Prop | Type | Default | Description |
|---|---|---|---|
| v-model | string | number | — | Shared binding for the selected value. Each Radio has a value; use the same name on all radios in the group. |
| default-checked | boolean | false | Initial selection for uncontrolled usage (without v-model). For interactive groups, prefer v-model. |
| Prop | Type | Default | Description |
|---|---|---|---|
| checked | boolean | — | Whether this radio is selected. Use onChange on each Radio in the group. |
| defaultChecked | boolean | — | Initial selection for uncontrolled usage. |
| onChange | ChangeEventHandler<HTMLInputElement> | — | Native input change handler. Each Radio has a value; use the same name on all radios in the group. |
| Prop | Type | Default | Description |
|---|---|---|---|
| name | string | — | The name attribute shared by radios in the same group. |
| endLabel | string | — | Label text after the control (LTR: right). |
| startLabel | string | — | Label text before the control (LTR: left). |
| description | string | — | Helper text below the control row. |
| error | boolean | false | Applies invalid styling and sets aria-invalid. |
| errorMessage | string | — | Error message shown below the control row. |
| required | boolean | false | Sets the native required attribute on the input. |
| disabled | boolean | false | Whether the radio is disabled. |
| color | RadioColor | "primary" | Semantic color of the radio. |
| size | RadioSize | "md" | Size of the control and label typography. |
| rounded | RadioRounded | "full" | Border radius of the radio control. |
| classes | RadioClasses | — | Classes for form control chrome and radio parts. |
| customProps | RadioCustomProps | — | Extra props for FormControl chrome and control parts. startLabel / endLabel accept Label props (no children). |
| slots | RadioSlots | — | React slots for chrome and the control. |