Radio
O componente Radio é um elemento de seleção única que permite ao usuário escolher uma opção de um grupo de alternativas mutuamente exclusivas. É ideal para formulários que requerem uma única seleção entre múltiplas opções.
Importação
import { Radio } from '@useblu/ocean-react';
Importação específica (recomendado para tree-shaking)
import { Radio } from '@useblu/ocean-react/Radio';
Importação de tipos TypeScript
import type { RadioProps } from '@useblu/ocean-react';
// Uso em componente customizado
const MyRadioGroup: React.FC<{
options: string[];
value: string;
onChange: (value: string) => void;
}> = ({ options, value, onChange }) => {
return (
<div>
{options.map((option) => (
<Radio
key={option}
label={option}
name="custom-group"
value={option}
checked={value === option}
onChange={(e) => onChange(e.target.value)}
/>
))}
</div>
);
};
Playground Interativo
Explore o componente Radio no playground interativo do Storybook:
Documentação Completa
Para documentação técnica detalhada, exemplos de uso e API completa, consulte o Storybook do Radio.
No Storybook você encontrará:
- ✅ Controles interativos para testar todas as props
- ✅ API gerada automaticamente com tipagem completa
- ✅ Exemplos visuais de todas as variantes e estados
- ✅ Playground para experimentação rápida
Uso básico
<Radio label="Opção selecionada" checked />
Grupo de Radios
Exemplo de grupo de radios interativo:
Estados
O Radio suporta diferentes estados visuais:
Sem label
Você pode usar o Radio sem label:
Estado de erro
O Radio suporta estado de erro com mensagem de validação exibida verticalmente abaixo do label:
<Radio label="Opção com erro" error errorMessage="Esta opção é obrigatória" />
Exemplo de validação em grupo
function RadioGroupValidation() {
const [selected, setSelected] = React.useState('');
const [touched, setTouched] = React.useState(false);
const hasError = touched && !selected;
return (
<div>
<h3>Selecione uma opção:</h3>
<Radio
label="Opção 1"
name="validation-group"
value="option1"
checked={selected === 'option1'}
onChange={(e) => setSelected(e.target.value)}
onBlur={() => setTouched(true)}
error={hasError}
/>
<Radio
label="Opção 2"
name="validation-group"
value="option2"
checked={selected === 'option2'}
onChange={(e) => setSelected(e.target.value)}
onBlur={() => setTouched(true)}
error={hasError}
/>
<Radio
label="Opção 3"
name="validation-group"
value="option3"
checked={selected === 'option3'}
onChange={(e) => setSelected(e.target.value)}
onBlur={() => setTouched(true)}
error={hasError}
errorMessage={
hasError ? 'Selecione uma opção para continuar' : undefined
}
/>
</div>
);
}
Exemplo de formulário
Exemplo prático de uso em formulário:
API
Props
| Prop | Tipo | Padrão | Descrição |
|---|---|---|---|
label | ReactNode | - | Texto do label do radio |
checked | boolean | false | Define se o radio está selecionado |
disabled | boolean | false | Desabilita o radio |
error | boolean | false | Define se o radio está em estado de erro |
errorMessage | string | - | Mensagem de erro exibida abaixo do label |
name | string | - | Nome do grupo de radios |
value | string | - | Valor do radio |
onChange | (event: ChangeEvent) => void | - | Função chamada quando o valor muda |
id | string | - | ID único do radio |
className | string | - | Classes CSS adicionais |
Classes CSS
O componente utiliza as seguintes classes CSS que podem ser customizadas:
| Classe | Descrição |
|---|---|
.ods-radio__root-container | Container wrapper do Radio |
.ods-radio__root | Container do label e input |
.ods-radio | Elemento input do radio |
.ods-radio__checkmark | Elemento visual do radio |
.ods-radio__checkmark--error | Modificador de erro no checkmark |
.ods-radio__label | Label do radio |
.ods-radio__error-message | Mensagem de erro abaixo do label |
Acessibilidade
- ✅ Suporte completo a navegação por teclado
- ✅ Estados de foco visíveis
- ✅ Atributos ARIA apropriados
- ✅ Suporte a screen readers
- ✅ Contraste adequado em todos os estados
Boas práticas
- Use
nameigual para todos os radios do mesmo grupo - Use
valueúnico para cada radio do grupo - Use
idúnico para cada radio - Use labels descritivos que expliquem a opção
- Use
aria-labelquando não houver label visível
Melhores práticas
✅ Faça
- Use para seleção única entre múltiplas opções
- Sempre agrupe radios relacionados com o mesmo
name - Use labels claros e descritivos
- Use valores únicos para cada radio
- Use estado
disabledquando apropriado - Organize radios verticalmente para melhor legibilidade
- Use
erroreerrorMessagepara feedback de validação - Exiba a mensagem de erro apenas no último radio do grupo
❌ Não faça
- Não use para seleção múltipla (use Checkbox)
- Não use o mesmo
namepara grupos diferentes - Não use valores duplicados no mesmo grupo
- Não use labels vagos ou genéricos
- Não ignore estados de foco e hover
- Não use para ações (use Button)
- Não exiba múltiplas mensagens de erro para o mesmo grupo
Casos de uso comuns
Seleção de gênero
function GenderSelection() {
const [gender, setGender] = React.useState('');
return (
<div>
<h3>Selecione seu gênero:</h3>
<Radio
label="Feminino"
name="gender"
value="female"
checked={gender === 'female'}
onChange={(e) => setGender(e.target.value)}
/>
<Radio
label="Masculino"
name="gender"
value="male"
checked={gender === 'male'}
onChange={(e) => setGender(e.target.value)}
/>
<Radio
label="Não binário"
name="gender"
value="non-binary"
checked={gender === 'non-binary'}
onChange={(e) => setGender(e.target.value)}
/>
</div>
);
}
Seleção de plano
function PlanSelection() {
const [selectedPlan, setSelectedPlan] = React.useState('basic');
return (
<div>
<h3>Escolha seu plano:</h3>
<Radio
label="Plano Básico - R$ 9,90/mês"
name="plan"
value="basic"
checked={selectedPlan === 'basic'}
onChange={(e) => setSelectedPlan(e.target.value)}
/>
<Radio
label="Plano Premium - R$ 19,90/mês"
name="plan"
value="premium"
checked={selectedPlan === 'premium'}
onChange={(e) => setSelectedPlan(e.target.value)}
/>
<Radio
label="Plano Enterprise - R$ 49,90/mês"
name="plan"
value="enterprise"
checked={selectedPlan === 'enterprise'}
onChange={(e) => setSelectedPlan(e.target.value)}
/>
</div>
);
}
Configurações de notificação
function NotificationSettings() {
const [notificationType, setNotificationType] = React.useState('email');
return (
<div>
<h3>Como você prefere receber notificações?</h3>
<Radio
label="Email"
name="notification"
value="email"
checked={notificationType === 'email'}
onChange={(e) => setNotificationType(e.target.value)}
/>
<Radio
label="SMS"
name="notification"
value="sms"
checked={notificationType === 'sms'}
onChange={(e) => setNotificationType(e.target.value)}
/>
<Radio
label="Push notification"
name="notification"
value="push"
checked={notificationType === 'push'}
onChange={(e) => setNotificationType(e.target.value)}
/>
<Radio
label="Não receber notificações"
name="notification"
value="none"
checked={notificationType === 'none'}
onChange={(e) => setNotificationType(e.target.value)}
/>
</div>
);
}
Seleção de idioma
function LanguageSelection() {
const [language, setLanguage] = React.useState('pt-BR');
return (
<div>
<h3>Selecione seu idioma:</h3>
<Radio
label="Português (Brasil)"
name="language"
value="pt-BR"
checked={language === 'pt-BR'}
onChange={(e) => setLanguage(e.target.value)}
/>
<Radio
label="English (US)"
name="language"
value="en-US"
checked={language === 'en-US'}
onChange={(e) => setLanguage(e.target.value)}
/>
<Radio
label="Español"
name="language"
value="es"
checked={language === 'es'}
onChange={(e) => setLanguage(e.target.value)}
/>
</div>
);
}
Radios desabilitados
function DisabledRadios() {
return (
<div>
<h3>Opções disponíveis:</h3>
<Radio
label="Opção disponível"
name="disabled-example"
value="available"
/>
<Radio
label="Opção indisponível"
name="disabled-example"
value="unavailable"
disabled
/>
<Radio
label="Opção selecionada"
name="disabled-example"
value="selected"
checked
/>
<Radio
label="Opção selecionada desabilitada"
name="disabled-example"
value="selected-disabled"
checked
disabled
/>
</div>
);
}
Radios sem label
function RadiosWithoutLabel() {
return (
<div>
<h3>Selecione uma opção:</h3>
<div>
<Radio name="no-label" value="option1" aria-label="Opção 1" />
<Radio name="no-label" value="option2" checked aria-label="Opção 2" />
<Radio name="no-label" value="option3" disabled aria-label="Opção 3" />
</div>
</div>
);
}
Links relacionados
- Checkbox - Seleção múltipla
- FormControl - Wrapper para campos de formulário
- FormLabel - Label de formulário
- Button - Botão para ações
- Storybook - Radio - Documentação técnica