HOWTO · React
Botón de radio en React
Este artículo presenta cómo implementar el botón de radio en react.
En esta página
Los botones de opción permiten elegir un valor entre un conjunto pequeño. En React, asigna a cada opción del mismo grupo un name compartido, un value distinto y una etiqueta legible. En los ejemplos siguientes, theme es el nombre del grupo, y DARK y LIGHT son los valores enviados. La etiqueta visible y el valor que recibe el controlador no tienen que ser el mismo texto.
Agrupar botones de opción con un mismo nombre
En JSX, un grupo puede escribirse con dos elementos <input type="radio" name="theme" value="DARK" /> y <input type="radio" name="theme" value="LIGHT" />, cada uno dentro de un <label> o asociado a un <label htmlFor="...">. El name compartido hace que el navegador trate los controles como una sola opción mutuamente excluyente; los valores distintos indican a la aplicación cuál se seleccionó. Si usas htmlFor, asigna un id único a cada control y asegúrate de que cada etiqueta identifique su propia opción. Así, los lectores de pantalla pueden interpretar los controles y las etiquetas permiten activarlos con un clic.
Gestionar una selección con el estado de React
En un formulario interactivo, guarda el valor seleccionado en el estado de React y actualízalo con un controlador onChange. Los ejemplos con estado de JSX suponen que useState se importa de React. Este componente de función completo inicializa theme con LIGHT, asigna el nombre compartido theme a los dos controles etiquetados y obtiene del estado el valor de cada prop checked: function ThemePicker() { const [theme, setTheme] = useState("LIGHT"); return (<fieldset><legend>Theme</legend>{[{ label: "Dark", value: "DARK" }, { label: "Light", value: "LIGHT" }].map((option) => (<label key={option.value}><input type="radio" name="theme" value={option.value} checked={theme === option.value} onChange={(event) => setTheme(event.target.value)} />{option.label}</label>))}</fieldset>); }. Cuando alguien selecciona Dark, target.value del evento es la cadena DARK; setTheme guarda ese valor y, en el siguiente renderizado, se marca el botón de opción correspondiente. La etiqueta visible y el valor enviado pueden ser distintos.
El evento de cambio de React se propaga desde el control seleccionado. onSubmit gestiona el envío del formulario, mientras que el onClick de un botón gestiona una acción de ese botón; ninguno sustituye a onChange para detectar un cambio en la selección. Al elegir cualquiera de las opciones, el controlador onChange lee su valor de cadena de event.target.value y lo guarda en theme. La demostración de PlayCode es un complemento interactivo opcional.
El diagrama sigue el valor desde el value del control hasta el estado; es un diagrama didáctico, no una captura de pantalla.
Ejecuta este ejemplo. Las etiquetas y la salida visible del bloque de código se mantienen en inglés.
const options = [
{ label: "Dark", value: "DARK" },
{ label: "Light", value: "LIGHT" },
];
let theme = "light";
const handleChange = (event) => {
theme = event.target.value;
};
handleChange({ target: { value: options[0].value } });
console.log(`Selected theme: ${theme}`);
Selected theme: DARK
Este ejemplo independiente de JavaScript representa el valor que pasa desde el control seleccionado hasta una actualización del estado. En un componente de React, useState proporciona la función de actualización y una prop checked vincula ese estado con los controles renderizados.
Renderizar opciones desde un array
Para una lista más larga, guarda las opciones en un array y usa .map() en JSX para generar un control etiquetado por cada opción. Este es un componente completo que renderiza la lista: const options = [{ label: "Blue", value: "blue" }, { label: "Green", value: "green" }]; function ColorOptions() { return (<fieldset><legend>Color</legend>{options.map((option) => (<label key={option.value}><input type="radio" name="color" value={option.value} />{option.label}</label>))}</fieldset>); }. El array proporciona una etiqueta y un valor distinto para cada opción; el mapeo devuelve una etiqueta y un control por opción. La key está en la etiqueta externa que devuelve .map(), lo que permite a React identificar cada elemento cuando cambia la lista. Ambos controles comparten name="color", por lo que el navegador los trata como un grupo de opciones mutuamente excluyentes. La expresión de JavaScript entre llaves de JSX evalúa el mapeo e inserta en la página los elementos que devuelve.
Elegir una selección inicial o controlada
Usa defaultChecked para inicializar un grupo no controlado cuando React no tenga que gestionar los cambios posteriores. Por ejemplo, un grupo completo de dos opciones puede escribirse así: function InitialTheme() { return (<fieldset><legend>Theme</legend><label><input type="radio" name="theme" value="DARK" defaultChecked />Dark</label><label><input type="radio" name="theme" value="LIGHT" />Light</label></fieldset>); }. El navegador gestiona las selecciones posteriores y solo la opción inicial prevista lleva defaultChecked.
Para crear un grupo controlado, guarda la selección en el estado, define la prop checked de cada control comparando el estado con su valor y actualiza el estado en onChange: function ControlledTheme() { const [theme, setTheme] = useState("DARK"); return (<fieldset><legend>Theme</legend><label><input type="radio" name="theme" value="DARK" checked={theme === "DARK"} onChange={(event) => setTheme(event.target.value)} />Dark</label><label><input type="radio" name="theme" value="LIGHT" checked={theme === "LIGHT"} onChange={(event) => setTheme(event.target.value)} />Light</label></fieldset>); }. Los valores de checked derivados del estado mantienen sincronizada la opción renderizada con React. Elige el patrón no controlado para la selección inicial o el patrón controlado; no combines defaultChecked y checked en un mismo control.
Extraer un componente reutilizable para grupos de botones de opción
Si varios formularios necesitan el mismo comportamiento, extrae un componente que reciba name, options, el value seleccionado y una función onChange. Esta implementación genera controles etiquetados a partir de las opciones, usa el valor de cada opción como clave estable y obtiene checked del valor seleccionado: function RadioGroup({ name, options, value, onChange }) { return (<fieldset><legend>{name}</legend>{options.map((option) => (<label key={option.value}><input type="radio" name={name} value={option.value} checked={value === option.value} onChange={(event) => onChange(event.target.value)} />{option.label}</label>))}</fieldset>); }. El componente padre gestiona el estado y pasa su función de actualización como controlador: function ThemeForm() { const [theme, setTheme] = useState("LIGHT"); const options = [{ label: "Dark", value: "DARK" }, { label: "Light", value: "LIGHT" }]; return <RadioGroup name="theme" options={options} value={theme} onChange={setTheme} />; }. El nombre compartido hace que las opciones sean mutuamente excluyentes, las etiquetas siguen asociadas a sus controles y el componente no crea una segunda copia del estado de selección. El mismo componente puede mostrar temas, colores u otras opciones cambiando sus props.