Tailwind CSS
Utility-First CSS: The Mental Model Shift
Traditional CSS: you write a class name, then style it in a separate CSS file:
/* In a .css file somewhere */
.booking-card {
background: white;
border-radius: 16px;
border: 1px solid #e2e8f0;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
overflow: hidden;
}
<div className="bg-white rounded-2xl border border-slate-100 shadow-sm overflow-hidden">
{/* same result, all inline */}
</div>
Every class is one CSS rule. You compose them like Lego bricks. At build time, Tailwind generates a CSS file with only the classes you actually use β no unused styles shipped.
The Naming System
| Class | CSS equivalent |
|---|---|
| bg-white | background-color: white |
| bg-teal-600 | background-color: #0d9488 |
| text-slate-900 | color: #0f172a |
| text-sm | font-size: 0.875rem |
| font-bold | font-weight: 700 |
| rounded-xl | border-radius: 0.75rem |
| rounded-2xl | border-radius: 1rem |
| p-4 | padding: 1rem (16px) |
| px-4 py-3 | padding: 0.75rem 1rem |
| flex gap-3 | display: flex; gap: 0.75rem |
| w-full | width: 100% |
| border border-slate-200 | border: 1px solid #e2e8f0 |
| shadow-sm | box-shadow: small shadow |
| transition-colors | transition: color, background-color, ... 150ms |
| animate-spin | animation: spin 1s linear infinite |
The Spacing Scale
Tailwind uses a consistent spacing scale where 1 unit = 4px:
p-1= 4px paddingp-2= 8pxp-4= 16pxp-6= 24pxp-8= 32pxgap-3= 12px gap between flex/grid children
State Variants: hover:, disabled:, focus:
Add a prefix to apply a class only in a certain state:
<button
onClick={() => handleManualConfirm(b.id)}
disabled={confirming === b.id}
className="
text-xs bg-amber-100 text-amber-800 font-medium
hover:bg-amber-200 /* darker on hover */
disabled:opacity-50 /* semi-transparent when disabled */
px-3 py-1.5 rounded-lg transition-colors whitespace-nowrap
"
>
{confirming === b.id ? 'Confirmingβ¦' : 'Confirm (Demo)'}
</button>
Responsive Prefixes: Mobile-First
Tailwind is mobile-first. Classes apply at all sizes; prefixes apply at breakpoints and above:
<div className="
grid
grid-cols-1 /* 1 column on mobile */
md:grid-cols-2 /* 2 columns on medium screens (768px+) */
lg:grid-cols-3 /* 3 columns on large screens (1024px+) */
gap-4
">
The Project's Color Palette
JongYang uses a consistent color system:
| Color | Class prefix | Used for |
|---|---|---|
| Teal | teal- | Primary CTA buttons, active states, brand color |
| Slate-900 | slate-900 | Dark backgrounds, admin panel |
| Slate-500 | slate-500 | Secondary text, labels |
| Slate-100 | slate-100 | Light borders, table hover backgrounds |
| Amber | amber- | Warnings, demo-only labels, pending_payment badges |
| Green | green- | confirmed status badges, LINE connected indicator |
| Red | red- | Error messages, cancelled status badges |
The Booking Status Badge Pattern
In the admin bookings page, status badges use a lookup object:
const STATUS_BADGE: Record<string, string> = {
confirmed: 'bg-green-100 text-green-800',
pending_payment: 'bg-amber-100 text-amber-800',
cancelled: 'bg-red-100 text-red-800',
}
// In the table row:
<span className={`inline-block px-2 py-0.5 rounded-full text-xs font-medium
${STATUS_BADGE[b.status] ?? 'bg-slate-100 text-slate-600'}`}>
{b.status.replace('_', ' ')}
</span>
The bg-green-100 text-green-800 pattern is standard Tailwind for colored badges β a light background color with a darker text of the same hue.
π§ Self-Check Quiz
1. What CSS does className="px-4 py-3" produce?
padding-left: 1rem; padding-right: 1rem; padding-top: 0.75rem; padding-bottom: 0.75rem; β that's 16px horizontal and 12px vertical. px- sets left+right padding; py- sets top+bottom. The number is the spacing scale (4 = 16px, 3 = 12px).2. What does hover:bg-amber-200 do and when does it apply?
background-color to amber-200 (#fde68a) only when the user hovers over the element. The hover: prefix is a state variant β without it, bg-amber-200 would apply at all times. In the demo confirm button, the background darkens from amber-100 to amber-200 on hover to give visual feedback.3. Tailwind is "mobile-first". What does md:grid-cols-2 mean?
grid-template-columns: repeat(2, minmax(0, 1fr)). On smaller screens (mobile), there's no effect from this class β whatever the base (non-prefixed) class says takes effect. Mobile-first means you design for small screens first, then add breakpoint prefixes for larger screens.4. What is the status badge pattern and why does it use bg-green-100 text-green-800 instead of just bg-green-800?
bg-green-800) with white text is harder to read at small sizes and looks harsh. The light background + dark text combination is more readable and visually softer β standard for status pills/chips in admin UIs.5. How does Tailwind know which classes to include in the final CSS file? Does it include all possible classes?
bg-pink-500 appears nowhere in your code, it won't be in the output CSS. This keeps the CSS file tiny. The build scans all .tsx, .ts, and .html files matching the content paths in the Tailwind config.