SSiddiq.in
Tailwind as a design language

The value of Tailwind isn't the utility classes. It's what they take away from you.

No random spacing values. No colour-of-the-week. No 4000-line stylesheet nobody dares open. Tailwind is a set of removed choices — and constraints are what let three engineers ship a coherent product.

The token layer

One file rebrands the whole app.

Everything in the product references semantic tokens, not raw values. That's the difference between a codebase you can rebrand in an afternoon and one you can't touch without regression testing 200 pages.

/* styles.css — one place, everything downstream inherits */
@theme {
  --color-ink: oklch(15% 0.01 90);
  --color-canvas: oklch(98% 0.005 90);
  --color-primary: oklch(88% 0.20 130);   /* rebrand here */
  --color-surface: var(--color-canvas);
  --color-surface-hover: color-mix(in oklch, var(--color-surface) 92%, var(--color-ink));

  --radius-card: 1rem;
  --spacing: 0.25rem;                     /* 4-based scale */
  --font-display: "Manrope", sans-serif;
}

/* usage anywhere */
<button class="bg-primary text-ink rounded-[--radius-card] px-6 py-3">
House rules we don't bend

The seven rules that keep it from turning into slop.

No hex codes in JSX

`text-[#3b82f6]` is a bug. If a colour isn't in the tokens, it doesn't belong on the page.

No arbitrary spacing (mostly)

`mt-[13px]` means the design system doesn't cover this case — either add a token or ask if 12/16 works.

Semantic > raw

`bg-surface` not `bg-white`. Dark mode is one property flip, not 400 file edits.

Compose in components, not JSX

If a button's class string appears twice, it's a component. Full stop.

cn() for conditional, not `${''}` templates

One utility function (tailwind-merge + clsx) resolves conflicts predictably.

Reset the reset

Preflight is a starting point, not gospel — override for prose blocks and rich-text CMS output.

Prettier plugin, always

class order is a religion. Automate it once and never discuss it again.

The rebrand test

Same components. Three brands. Twelve lines changed.

Fintech — Klara
Ship faster with clarity.
Get started →
D2C — Catterce
Ship faster with clarity.
Get started →
SaaS — FlowMetric
Ship faster with clarity.
Get started →

Tailwind FAQ

Inline styles have no constraints — anyone can write `padding: 13px`. Tailwind's utilities compose from a token config (spacing, colour, radius, type). It's the difference between paint and paint-by-numbers: same medium, wildly different outcomes at scale.

Tailwind anti-patterns

Six habits that turn Tailwind's speed advantage into a maintenance tax.

Arbitrary values everywhere
`text-[13px] p-[7px] mt-[11px]` — you've re-invented inline styles, badly. Extend the theme scale instead.
@apply as a component system
`.btn { @apply px-4 py-2 ... }` scattered across CSS files. React components are the component system. @apply exists for prose + third-party overrides.
Ignoring the design system
`bg-blue-500` when the token is `bg-primary`. Every hardcoded colour is a future migration.
Long strings, no order
35 utility classes in random order. Pick an ordering (layout → box → typography → colour → state) and enforce with Prettier + tailwindcss plugin.
Repeating variants inline
`hover:bg-primary/90 focus-visible:bg-primary/90 active:bg-primary/90 disabled:bg-primary/50` on 40 buttons. Extract a component.
Fighting the JIT
Dynamic class names built by string concat (`text-${size}`). Tailwind can't see them → not generated. Use full class names in a switch, or `cn()` with variants.

Turn your Figma into a token system.

Book a design-system call
Right tech, honest advice

Not sure if this is the right stack for you?

Tell us your goals — we'll recommend the right technology honestly, even if it isn't this one.

  • Personal reply from Siddiq within 24 hours
  • Honest advice — no pushy sales, no fake urgency
  • Clear next steps, timeline, and estimate

We only use your details to reply to this enquiry. Privacy.