Frontend Development

Modern CSS in 2026 — Tailwind v4, Open Props, and CUBE CSS Architecture

By Domain India Team · DomainIndia EngineeringPublished 8 min read
Knowledge base article
Contents (24 sections)

Writing CSS has changed a lot in the last few years. Browsers now ship nesting, container queries, :has() and modern colour functions, and the popular tools have been rebuilt around them. This guide compares three current approaches (Tailwind CSS v4, Open Props and CUBE CSS) and shows the native features worth using.

Key takeaways

Tailwind v4 is configured in CSS instead of JavaScript and builds much faster than v3. Open Props gives you design tokens as plain CSS variables without a framework, and CUBE CSS is a methodology for teams that want structure without lock-in. Whichever you pick, the output is ordinary CSS that you build on your computer and upload to any hosting.

1. The landscape today

ApproachBundle sizeDXLearning curveFit
Utility-first (Tailwind v4)Small; only classes you useExcellentModerateProduct teams
Design tokens (Open Props)Small; import only the parts you needGoodLowDesigners who like pure CSS
Modular architecture (CUBE CSS)VariesGreat long-termHigh initiallyLong-lived projects
CSS-in-JS (styled-components etc.)Runtime costGoodModerateReact-heavy SPAs
Vanilla CSS + modern featuresSmallestDependsLowSmall sites

No single answer. Small marketing site? Vanilla CSS. Product UI with a team? Tailwind or CUBE. Design system? Open Props.

2. Tailwind v4: what's new

Tailwind CSS v4.0 was released in January 2025 and is the current major version:

  • Faster builds: a new engine (partly written in Rust) that the Tailwind team reports is several times faster than v3 for full builds, and far faster for incremental ones
  • Zero config for most projects — no tailwind.config.js needed, works with @import "tailwindcss"
  • CSS-first configuration — customise in CSS, not JS config file
  • Container queries built in
  • Auto content detection — scans your HTML/JS/TS without the content: array
  • Native CSS cascade layers used for predictable specificity

Setup (Vite project)

bash
npm install tailwindcss @tailwindcss/vite

vite.config.ts:

typescript
import tailwindcss from '@tailwindcss/vite';

export default {
  plugins: [tailwindcss()],
};

src/app.css:

css
@import "tailwindcss";

/* Customise inline — no separate config file */
@theme {
  --color-brand-50: oklch(0.98 0.02 260);
  --color-brand-500: oklch(0.6 0.2 260);
  --color-brand-900: oklch(0.2 0.1 260);

  --font-sans: "Inter", sans-serif;

  --spacing: 0.25rem;    /* default spacing unit */
}

Use in HTML:

html
<button class="bg-brand-500 text-white px-6 py-3 rounded-lg hover:bg-brand-900">
  Click
</button>

v4 migration from v3

bash
npx @tailwindcss/upgrade

The upgrade tool (it needs Node.js 20 or later) rewrites most of your config and templates. Check these by hand afterwards:

  • ring now defaults to 1px (it was 3px); use ring-3 for the old look.
  • bg-opacity-* is gone; use the slash syntax, for example bg-black/50.
  • Some scales were renamed: the old shadow-sm is now shadow-xs, and rounded-sm is now rounded-xs.
  • Borders and rings now default to currentColor instead of grey.
  • The space-y-* selector changed; flex flex-col gap-4 is usually the cleaner replacement.
  • Plugins are loaded in CSS, for example @plugin "@tailwindcss/forms";.

3. Open Props: design tokens as CSS variables

Open Props is a set of CSS files full of custom properties (variables). There's no framework, and you can use it with or without a build step.

bash
npm install open-props
# or link it from a CDN such as unpkg
css
@import "open-props/style";
@import "open-props/normalize";

.card {
  background: var(--surface-2);
  padding: var(--size-fluid-3);
  border-radius: var(--radius-3);
  box-shadow: var(--shadow-3);
  color: var(--text-1);
}

.button {
  background: var(--blue-6);
  color: white;
  padding: var(--size-2) var(--size-4);
  border-radius: var(--radius-2);
  transition: background var(--ease-3) 150ms;
}
.button:hover {
  background: var(--blue-7);
}

Includes:

  • Colours (a palette of hues and shades; the normalize file adds light and dark surfaces)
  • Spacing (fixed and fluid sizes)
  • Shadows
  • Border radius
  • Animations and easings
  • Gradients
  • Custom media queries such as --md-n-above. These are not variables: @media (--md-n-above) needs a build step such as PostCSS with postcss-custom-media

No class pollution — just tokens. Pair with your own selectors or other frameworks.

4. CUBE CSS: architecture without a framework

CUBE = Composition, Utility, Block, Exception. A methodology, not a library.

The four layers

  1. Composition — global layout rules (macro level)
  2. Utility — single-purpose classes for small adjustments
  3. Block — named components with their own styles
  4. Exception — rare one-off overrides via data-attributes

Example folder structure

code
styles/
├── composition/
│   ├── stack.css       /* vertical rhythm */
│   ├── cluster.css     /* horizontal groups */
│   ├── sidebar.css     /* content + sidebar layout */
├── utilities/
│   ├── color.css
│   ├── text.css
│   ├── spacing.css
├── blocks/
│   ├── card.css
│   ├── nav.css
│   ├── form.css
├── exceptions/         /* data-state overrides */
├── tokens.css          /* CSS custom properties */
└── main.css            /* imports all */

Stack (composition primitive)

css
.stack {
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
}
.stack > * + * {
  margin-block-start: var(--space-m);
}
html
<section class="stack">
  <h1>Welcome</h1>
  <p>Article content…</p>
  <button>Read more</button>
</section>

Every direct child gets consistent spacing. No per-component margin tweaks.

Block (component)

css
.card {
  background: var(--surface-2);
  padding: var(--space-m);
  border-radius: var(--radius-3);
}
.card__title {
  font-size: var(--font-size-3);
  font-weight: 600;
}
.card__body {
  color: var(--color-text-2);
}

Exception (state overrides)

css
[data-state="open"] { display: block; }
[data-state="closed"] { display: none; }
[data-loading="true"] .card { opacity: 0.5; pointer-events: none; }

5. Modern CSS features worth using

Container queries

css
.card-grid {
  container-type: inline-size;
}

.card {
  padding: var(--space-s);
}

@container (min-width: 600px) {
  .card {
    display: grid;
    grid-template-columns: 150px 1fr;
    padding: var(--space-m);
  }
}

Responsive based on parent size, not viewport. Killer for reusable components.

:has() — parent selection

css
form:has(:invalid) button[type="submit"] {
  opacity: 0.5;
  pointer-events: none;
}

CSS nesting (native)

css
.card {
  padding: var(--space-m);

  & h2 {
    font-size: var(--font-size-3);
  }

  &:hover {
    transform: translateY(-2px);
  }
}

No preprocessor needed.

color-mix() and oklch

css
:root {
  --brand: oklch(0.6 0.2 260);
  --brand-lighter: color-mix(in oklch, var(--brand) 70%, white);
}

oklch gives perceptually-uniform colors — no more "muddy" gradients.

@scope

css
@scope (.card) {
  h2 { color: var(--brand); }
}

Styles only apply inside the scope, which is cleaner than BEM naming for component isolation. @scope is now in current versions of Chrome, Edge, Safari and Firefox, but older browsers lack it, so check your audience's browsers before relying on it.

6. Which to choose?

Marketing sites and simple apps
Tailwind v4 is the fastest to ship.
Multi-team design system
Open Props for shared tokens, plus your own classes.
Long-lived product with strict accessibility or brand rules
CUBE CSS is the easiest to maintain.
Small sites and experiments
Vanilla CSS with nesting and container queries.
React apps with strict component scoping
CSS Modules or Tailwind.

7. Migration tips

From Bootstrap → Tailwind

  • Replace grid classes: col-md-6 → md:w-1/2
  • Forms: use the @tailwindcss/forms plugin (@plugin "@tailwindcss/forms"; in v4)
  • Components: build your own; copy from ui.shadcn.com (free)

From CSS-in-JS → vanilla + tokens

  • Extract colors, spacing, fonts to CSS variables
  • Move component styles to CSS files
  • Tree-shake styled-components/emotion packages

8. Hosting a modern CSS site on Domain India

Tailwind, Open Props and CUBE CSS all produce plain CSS files. Run the build on your own computer or in CI, then upload the output (for example Vite's dist/ folder) to public_html with the File Manager or FTP. Nothing needs to run on the server, so this works on cPanel hosting and DirectAdmin hosting. For WordPress or Laravel themes, build the CSS locally too and upload the compiled file with your theme. Shared hosting already compresses CSS for you, so there's nothing extra to switch on.

9. Common pitfalls

Utility class bloat in HTML
Twenty classes on one element is hard to read. Extract a component (or use @apply sparingly).
Mixing approaches inconsistently
Half Tailwind and half CSS-in-JS is hard to maintain. Pick one primary approach.
Fighting specificity with utilities
A utility can lose to a more specific selector. In v4 the important modifier goes at the end (text-red-500!); use it sparingly.
Over-designing tokens
Hundreds of spacing variables nobody uses. Start with 8-10 sizes and add more only when needed.
Skipping the reset
Use open-props/normalize, Tailwind's Preflight or a similar reset. Browsers differ more than you think.

FAQ

Tailwind or vanilla CSS for small site?

For <10 pages with no team: vanilla CSS + Open Props is faster to write and understand. Tailwind shines when you have many pages or components to keep consistent.

Does Tailwind v4 work with WordPress / Laravel / Rails?

Yes — it's a CSS tool, framework-agnostic. Configure the build step to watch your templates.

Performance impact of Tailwind?

Tailwind generates only the classes you use, so production CSS is usually small, often smaller than a full Bootstrap stylesheet. Check your own build output to be sure.

Should I use CSS-in-JS in 2026?

Declining trend. Modern browser features (scoping, nesting, container queries) + vanilla CSS + tokens cover most cases without runtime cost.

Dark mode implementation?

color-scheme: light dark + prefers-color-scheme media query. Use CSS variables; flip values in @media (prefers-color-scheme: dark). Tailwind v4's dark: variant follows prefers-color-scheme by default, and you can switch it to a class or data attribute with @custom-variant.

Ready to publish your site? Upload the built files to cPanel hosting or DirectAdmin hosting. Questions about your plan? Open a support ticket.

Ship your next site

Modern CSS builds to plain files that run on any Domain India hosting plan.

See hosting plans

Was this article helpful?

Your answer helps us decide what to improve next.

Still need help? Open a support ticket and our team will reply.

Prefer an app? Add this site to your home screen.Get the app