# Next.js Bootstrap Checkbox and Radio

Next.js Bootstrap checkbox, radio and switch markup: plain checks in server components, and toggle buttons that keep their state in a client component.

Use a checkbox for an option people turn on or off, and radios when they pick one choice out of a few. A switch is a checkbox drawn as a toggle. AdminKit for Next.js draws all three with Bootstrap's `.form-check` markup in JSX. They are in the free and PRO versions of [AdminKit for Next.js](/nextjs/). In JSX, set the starting state with `defaultChecked`, not `checked`.

Because they are plain markup, not components, a page that only renders them stays a server component. It renders on the server and needs no `"use client"`. When the checked state drives something else on the page, that state has to live in the browser. Move the checks into a client component, a file that starts with `"use client"`, and use `checked` and `onChange`, as shown below.

## Example

```html
<div class="form-check">
  <input class="form-check-input" type="checkbox" value="" id="checkDefault">
  <label class="form-check-label" for="checkDefault">Email me about new comments</label>
</div>
<div class="form-check">
  <input class="form-check-input" type="checkbox" value="" id="checkChecked" checked>
  <label class="form-check-label" for="checkChecked">Email me a weekly summary</label>
</div>
```
```tsx code
<div className="form-check">
  <input className="form-check-input" type="checkbox" value="" id="checkDefault" />
  <label className="form-check-label" htmlFor="checkDefault">Email me about new comments</label>
</div>
<div className="form-check">
  <input className="form-check-input" type="checkbox" value="" id="checkChecked" defaultChecked />
  <label className="form-check-label" htmlFor="checkChecked">Email me a weekly summary</label>
</div>
```

The demo pages also use a form without ids: a `<label class="form-check">` wraps the input and a `<span class="form-check-label">`.

## Classes

| Class | Element | Description |
| --- | --- | --- |
| `form-check` | wrapper | Lays out the input and its label |
| `form-check-input` | `<input>` | The checkbox or radio |
| `form-check-label` | `<label>`, `<span>` | The label text |
| `form-check-inline` | `.form-check` | Puts the checks on one line |
| `form-switch` | `.form-check` | Draws a checkbox as a switch |
| `btn-check` | `<input>` | Hides the input; its `.btn` label becomes a toggle button |

## Radios

For one choice out of a few, give the radios the same `name`. They then form one group.

```html
<div class="form-check">
  <input class="form-check-input" type="radio" name="plan" value="monthly" id="radioMonthly" checked>
  <label class="form-check-label" for="radioMonthly">Monthly</label>
</div>
<div class="form-check">
  <input class="form-check-input" type="radio" name="plan" value="yearly" id="radioYearly">
  <label class="form-check-label" for="radioYearly">Yearly</label>
</div>
<div class="form-check">
  <input class="form-check-input" type="radio" name="plan" value="lifetime" id="radioLifetime" disabled>
  <label class="form-check-label" for="radioLifetime">Lifetime</label>
</div>
```
```tsx code
<div className="form-check">
  <input className="form-check-input" type="radio" name="plan" value="monthly" id="radioMonthly" defaultChecked />
  <label className="form-check-label" htmlFor="radioMonthly">Monthly</label>
</div>
<div className="form-check">
  <input className="form-check-input" type="radio" name="plan" value="yearly" id="radioYearly" />
  <label className="form-check-label" htmlFor="radioYearly">Yearly</label>
</div>
<div className="form-check">
  <input className="form-check-input" type="radio" name="plan" value="lifetime" id="radioLifetime" disabled />
  <label className="form-check-label" htmlFor="radioLifetime">Lifetime</label>
</div>
```

Add `form-check-inline` to each `.form-check` to put them on one line.

## Switches

For a setting, add `form-switch` to the `.form-check`. The checkbox is then drawn as a switch:

```html
<div class="form-check form-switch">
  <input class="form-check-input" type="checkbox" id="switchDefault">
  <label class="form-check-label" for="switchDefault">Default switch checkbox input</label>
</div>
<div class="form-check form-switch">
  <input class="form-check-input" type="checkbox" id="switchChecked" checked>
  <label class="form-check-label" for="switchChecked">Checked switch checkbox input</label>
</div>
<div class="form-check form-switch">
  <input class="form-check-input" type="checkbox" id="switchDisabled" disabled>
  <label class="form-check-label" for="switchDisabled">Disabled switch checkbox input</label>
</div>
```
```tsx code
<div className="form-check form-switch">
  <input className="form-check-input" type="checkbox" id="switchDefault" />
  <label className="form-check-label" htmlFor="switchDefault">Default switch checkbox input</label>
</div>
<div className="form-check form-switch">
  <input className="form-check-input" type="checkbox" id="switchChecked" defaultChecked />
  <label className="form-check-label" htmlFor="switchChecked">Checked switch checkbox input</label>
</div>
<div className="form-check form-switch">
  <input className="form-check-input" type="checkbox" id="switchDisabled" disabled />
  <label className="form-check-label" htmlFor="switchDisabled">Disabled switch checkbox input</label>
</div>
```

## Controlled toggle buttons

When a choice has to update other parts of the page, its state lives in a client component. The billing period toggle of the Pricing page works like this: two `.btn-check` radios whose `checked` comes from state.

```html
<div class="btn-group" role="group" aria-label="Billing period">
  <input type="radio" class="btn-check" name="billing-period" id="billingMonthly" value="monthly" autocomplete="off" checked>
  <label class="btn btn-outline-primary" for="billingMonthly">Monthly</label>
  <input type="radio" class="btn-check" name="billing-period" id="billingYearly" value="yearly" autocomplete="off">
  <label class="btn btn-outline-primary" for="billingYearly">Yearly</label>
</div>
```
```tsx code title="src/components/billing-period-toggle.tsx"
"use client";

import { useState } from "react";

export function BillingPeriodToggle() {
  const [period, setPeriod] = useState<"monthly" | "yearly">("monthly");

  return (
    <div className="btn-group" role="group" aria-label="Billing period">
      <input
        type="radio"
        className="btn-check"
        name="billing-period"
        id="billingMonthly"
        value="monthly"
        autoComplete="off"
        checked={period === "monthly"}
        onChange={() => setPeriod("monthly")}
      />
      <label className="btn btn-outline-primary" htmlFor="billingMonthly">Monthly</label>
      <input
        type="radio"
        className="btn-check"
        name="billing-period"
        id="billingYearly"
        value="yearly"
        autoComplete="off"
        checked={period === "yearly"}
        onChange={() => setPeriod("yearly")}
      />
      <label className="btn btn-outline-primary" htmlFor="billingYearly">Yearly</label>
    </div>
  );
}
```

In the demo, a context provider holds the period, so the prices elsewhere on the server-rendered page follow the toggle. The state starts at `"monthly"` on the server and in the browser. That keeps hydration, the browser taking over the server HTML, free of mismatches.

For a checkbox, read `event.target.checked` in `onChange`. A `checked` without `onChange` is read-only, and React warns about it.

## Accessibility

- Label each check: `<label htmlFor>` with the input's `id`, a wrapping `<label>`, or `aria-label` without visible text.
- Put a group of radios or checkboxes in a `<fieldset>` with a `<legend>`, or give it `role="group"` and an `aria-label`.
- Screen readers announce a switch as a checkbox, so its label should name the setting it turns on.
- `.btn-check` inputs are hidden visually but stay focusable: Tab and the arrow keys reach the toggle buttons.

## Related

- [React Bootstrap checkbox and radio](/react/docs/forms/checkbox-radio/): the same checks in AdminKit for React (Vite)
- [Bootstrap 5 checkbox](/bootstrap/docs/forms/checkbox/), [radio](/bootstrap/docs/forms/radio/) and [toggle switch](/bootstrap/docs/forms/toggle-switch/): the checks of the HTML version
- [Form layout](/nextjs/docs/forms/layout/): checks in horizontal and inline forms
- [Basic Inputs demo](https://nextjs-demo.adminkit.io/forms-basic-inputs)

---

Canonical HTML page: https://adminkit.io/nextjs/docs/forms/checkbox-radio/

Site overview for agents: https://adminkit.io/llms.txt (expanded: https://adminkit.io/llms-full.txt) · Documentation: https://adminkit.io/bootstrap/docs/ · Questions: support@adminkit.io
