Search

Ctrl + K

Radio

This document outlines the steps to create Radio component styled withTailwind CSS and using some npm dependency libraries.

Prerequisites

  • Node.js and npm installed on your machine.
  • Tailwind CSS installed in your project.
  • CVA(class-variance-authority) is a utility for managing CSS class names based on various conditions.
  • clsx is a tiny utility for constructing className strings conditionally.
Step 1: Create variant styles
1// radio.helpers.ts
2import { cva } from "class-variance-authority";
3
4export const radioVariants = cva(
5  "w-6 h-6 rounded-full flex justify-center items-center border text-white bg-white",
6  {
7    variants: {
8      inputSize: {
9        small: "w-5 h-5 border data-[checked=true]:border-[6px]",
10        medium: "w-6 h-6 border-2 data-[checked=true]:border-[8px]",
11        large: "w-8 h-8 border-[3px] data-[checked=true]:border-[10px]",
12      },
13      radioColor: {
14        primary: "border-blue-500 data-[disabled=true]:border-blue-300",
15        secondary: "border-gray-500 data-[disabled=true]:border-gray-300",
16        success: "border-green-500 data-[disabled=true]:border-green-300",
17        danger: "border-red-500 data-[disabled=true]:border-red-300",
18        warning: "border-yellow-500 data-[disabled=true]:border-yellow-300",
19        info: "border-cyan-500 data-[disabled=true]:border-cyan-300",
20        light: "border-gray-300 data-[disabled=true]:border-gray-200",
21        dark: "border-black data-[disabled=true]:border-gray-500",
22      },
23    },
24    defaultVariants: {
25      inputSize: "medium",
26      radioColor: "primary",
27    },
28  },
29);
30
31export const labelVariants = cva(
32  "cursor-pointer select-none pl-2 font-medium",
33  {
34    variants: {
35      inputSize: {
36        small: "text-xs",
37        medium: "text-sm",
38        large: "text-lg",
39      },
40    },
41    defaultVariants: {
42      inputSize: "medium",
43    },
44  },
45);
46
Step 2: Create Radio component
1// radio.component.tsx
2import clsx from "clsx";
3import { useId } from "react";
4import type { VariantProps } from "class-variance-authority";
5import { labelVariants, radioVariants } from "./radio.helpers";
6
7export interface RadioProps
8  extends React.InputHTMLAttributes<HTMLInputElement>,
9    VariantProps<typeof radioVariants> {
10  checked: boolean;
11  label?: string;
12  className?: string;
13  onChangeChecked?: (
14    checked: boolean,
15    value: readonly string[] | string | number | undefined,
16  ) => void;
17}
18
19const Radio: React.FC<RadioProps> = ({
20  radioColor,
21  inputSize,
22  value,
23  label,
24  checked,
25  disabled,
26  className,
27  onChangeChecked,
28  ...props
29}) => {
30  const id = useId();
31
32  return (
33    <div className={cn("flex items-center", className)}>
34      <div className="relative cursor-pointer">
35        <div
36          data-disabled={Boolean(disabled).toString()}
37          data-checked={Boolean(checked).toString()}
38          className={radioVariants({ inputSize, radioColor })}
39        />
40        <input
41          {...props}
42          type="radio"
43          id={id}
44          disabled={disabled}
45          checked={checked}
46          onChange={(e) => onChangeChecked?.(e.target.checked, value)}
47          className="absolute inset-0 cursor-pointer opacity-0"
48        />
49      </div>
50      {label && (
51        <label htmlFor={id} className={labelVariants({ inputSize })}>
52          {label}
53        </label>
54      )}
55    </div>
56  );
57};
58
59export default Radio;
60