Формыradiogroup
Custom Radio Group
Группа радиокнопок в виде карточек с иконками и активной подсветкой границ.
Живое превью
Использование
Скопируйте и вставьте этот код в ваш React-компонент:
tsx
import { CustomRadioGroup } from 'react-component-kit-ui/forms';
<CustomRadioGroup label="Select your billing cycle" name="billing" options={[
{ label: "Monthly", value: "monthly" },
{ label: "Yearly (Save 20%)", value: "yearly", checked: true },
{ label: "Lifetime", value: "life" }
]} />Ручная установка
Если вы не используете пакет npm, создайте файл и вставьте следующий код: src/components/CustomRadioGroup.tsx + CustomRadioGroup.css:
CustomRadioGroup.tsx
'use client';
import './CustomRadioGroup.css';
/** class:list → className */
function cx(...args: unknown[]): string {
const out: string[] = [];
const walk = (v: unknown) => {
if (!v) return;
if (typeof v === 'string' || typeof v === 'number') out.push(String(v));
else if (Array.isArray(v)) v.forEach(walk);
else if (typeof v === 'object') for (const [k, on] of Object.entries(v as Record<string, unknown>)) if (on) out.push(k);
};
args.forEach(walk);
return out.join(' ');
}
/**
* CustomRadioGroup — A group of styled radio buttons for vertical or horizontal options.
*
* @param {string} label - Optional title for the fieldset.
* @param {string} name - Common HTML name for the radio group.
* @param {Array<{label: string, value: string, checked?: boolean}>} options - List of choices.
* @param {boolean} horizontal - Layout orientation. Default is false (vertical).
*/
export interface CustomRadioGroupProps {
label?: string;
name: string;
options: Array<{ label: string; value: string; checked?: boolean }>;
horizontal?: boolean;
}
export function CustomRadioGroup({ label, name, options = [], horizontal = false }: CustomRadioGroupProps) {
return (
<>
<fieldset className={cx(["radio-group", { "radio-group--horizontal": horizontal }])} data-rk-01df88="">
{label && <legend className="radio-group-legend" data-rk-01df88="">{label}</legend>}
<div className="radio-items" data-rk-01df88="">
{options.map((opt, i) => (
<label key={i} className="radio-item" data-rk-01df88="">
<input type="radio" name={name} defaultValue={opt.value} defaultChecked={opt.checked} data-rk-01df88="" />
<span className="radio-circle" aria-hidden="true" data-rk-01df88=""></span>
<span className="radio-label" data-rk-01df88="">{opt.label}</span>
</label>
))}
</div>
</fieldset>
</>
);
}
export default CustomRadioGroup;CustomRadioGroup.css
/* CustomRadioGroup — ported from astro-component-kit (forms/CustomRadioGroup.astro) */
.radio-group:where([data-rk-01df88]) { border: none; padding: 0; margin: 0; width: 100%; }
.radio-group-legend:where([data-rk-01df88]) { font-size: 0.85rem; font-weight: 600; color: var(--c-text-2, #94a3b8); margin-bottom: var(--sp-3, 0.75rem); margin-left: 0.5rem; }
.radio-items:where([data-rk-01df88]) { display: flex; flex-direction: column; gap: var(--sp-3, 0.8rem); }
.radio-group--horizontal:where([data-rk-01df88]) .radio-items:where([data-rk-01df88]) { flex-direction: row; flex-wrap: wrap; gap: var(--sp-6, 1.5rem); }
.radio-item:where([data-rk-01df88]) { display: flex; align-items: center; gap: 0.75rem; cursor: pointer; color: var(--c-text-2, #94a3b8); transition: 0.2s; user-select: none; }
.radio-item:where([data-rk-01df88]) input:where([data-rk-01df88]) { position: absolute; opacity: 0; width: 1px; height: 1px; margin: 0; pointer-events: none; }
.radio-item:where([data-rk-01df88]) { position: relative; }
.radio-item:where([data-rk-01df88]) input:focus-visible:where([data-rk-01df88]) + .radio-circle:where([data-rk-01df88]) { outline: 2px solid var(--c-primary-light, #818cf8); outline-offset: 2px; }
.radio-circle:where([data-rk-01df88]) {
width: 20px; height: 20px;
border: 2px solid var(--c-border, #334155);
border-radius: var(--r-full, 50%);
position: relative; cursor: pointer; transition: 0.2s;
background: var(--c-bg-elev, rgba(255,255,255,0.02));
}
.radio-item:hover:where([data-rk-01df88]) .radio-circle:where([data-rk-01df88]) { border-color: var(--c-primary-light, #818cf8); }
.radio-circle:where([data-rk-01df88])::after {
content: ''; position: absolute; inset: 4px;
background: var(--c-primary, #6366f1);
border-radius: 50%; opacity: 0; transform: scale(0.5); transition: 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}
.radio-item:where([data-rk-01df88]) input:checked:where([data-rk-01df88]) + .radio-circle:where([data-rk-01df88]) { border-color: var(--c-primary, #6366f1); box-shadow: 0 0 10px rgba(99, 102, 241, 0.2); }
.radio-item:where([data-rk-01df88]) input:checked:where([data-rk-01df88]) + .radio-circle:where([data-rk-01df88])::after { opacity: 1; transform: scale(1); }
.radio-label:where([data-rk-01df88]) { font-size: 0.95rem; }
.radio-item:where([data-rk-01df88]) input:checked:where([data-rk-01df88]) ~ .radio-label:where([data-rk-01df88]) { color: var(--c-text-1, #fff); font-weight: 600; }Краткая информация
- Категория
- Формы
- Имя файла
CustomRadioGroup.tsx- Зависимости
- Нет — чистый React + CSS
- Теги
- radiogroup