Good Code
The good version separates base structure, visual tone, and interaction states. A reviewer can scan each concern and spot duplicate or conflicting utilities quickly.
Lesson 01
Group Tailwind utilities by purpose so reviewers can understand layout, color, state, and motion without decoding one long string.
type PrimaryButtonProps = {
children: React.ReactNode;
disabled?: boolean;
};
const baseClasses =
// Layout and sizing live together.
"inline-flex h-10 items-center justify-center gap-2 rounded-md px-4 text-sm font-medium";
const toneClasses =
// Color, shadow, and hover tone live together.
"bg-sky-600 text-white shadow-sm hover:bg-sky-500";
const stateClasses =
// Focus and disabled styles live together.
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-sky-300 disabled:cursor-not-allowed disabled:opacity-50";
export function PrimaryButton({ children, disabled }: PrimaryButtonProps) {
return (
<button
type="button"
disabled={disabled}
className={[baseClasses, toneClasses, stateClasses].join(" ")}
>
{children}
</button>
);
}export function PrimaryButton({ children, disabled }) {
// One long className mixes layout, color, state, and a duplicate radius.
return (
<button
disabled={disabled}
className="px-4 text-white rounded-md h-10 bg-sky-600 text-sm hover:bg-sky-500 inline-flex shadow-sm items-center disabled:opacity-50 justify-center font-medium focus-visible:ring-2 gap-2 rounded-lg disabled:cursor-not-allowed focus-visible:ring-sky-300"
>
{children}
</button>
);
}The good version separates base structure, visual tone, and interaction states. A reviewer can scan each concern and spot duplicate or conflicting utilities quickly.
The bad version ships one long class list with mixed concerns and an accidental rounded value conflict. The UI may render, but the intent is harder to review.