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. 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
<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 className="form-check"> wraps the input and a <span className="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.
<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:
<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.
"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'sid, a wrapping<label>, oraria-labelwithout visible text. - Put a group of radios or checkboxes in a
<fieldset>with a<legend>, or give itrole="group"and anaria-label. - Screen readers announce a switch as a checkbox, so its label should name the setting it turns on.
.btn-checkinputs are hidden visually but stay focusable: Tab and the arrow keys reach the toggle buttons.
Related
- React Bootstrap checkbox and radio: the same checks in AdminKit for React (Vite)
- Bootstrap 5 checkbox, radio and toggle switch: the checks of the HTML version
- Form layout: checks in horizontal and inline forms
- Basic Inputs demo
Last updated on
Select
Next.js React Select in AdminKit PRO: a searchable, Bootstrap-styled select with groups and multiple values that renders cleanly on the server.
Input maskPro
A Next.js input mask for the App Router in AdminKit PRO: a client component that loads Inputmask in the browser and masks dates, amounts and IP addresses.