Skip to main content

Advanced: Build a real page with Tailwind CSS 4

After the basic environment is built, the real challenge comes from "how to apply abstract atomic classes to real business." This article selects common page modules of mini programs, combines them with the new instructions of tailwindcss@4, and summarizes a set of processes from design disassembly to code implementation.

Tool-first mental model

The core of Tailwind CSS is not to memorize formulas, but to split the UI into three dimensions: "layout", "typesetting" and "state", and then use class name combinations to quickly assemble it. Tailwind 4 further introduces instructions such as @theme and @utility to synchronize customization capabilities with project constraints:

  • @theme Manage design tokens: color, spacing, font size, shadow, etc.
  • @utility declares a reusable tool class, replacing the traditional .btn { ... }
  • @variant / @custom-variant management status class (such as dark: and business attribute status)

Once you master these directives, you can extend Tailwind without leaving CSS syntax.

Mini program interaction status

Mini program does not support CSS :active. weapp-tailwindcss deletes the selector generated by active:* from the applet style product by default, but the web construction of H5 and App will still be retained. For applet press feedback, hover-class of the component should be used first.

1. Disassemble a card component

Taking "Order Card" as an example, first write the skeleton in src/components/order-card/index.vue:

src/components/order-card/index.vue
<template>
<view class="order-card">
<view class="order-card__header">
<text class="order-card__title">{{ title }}</text>
<text class="order-card__status" :class="statusClass">{{ statusText }}</text>
</view>
<view class="order-card__meta">
<text>{{ createdAt }}</text>
<text>{{ amount }}</text>
</view>
<slot />
</view>
</template>

Next, use the Tailwind atomic class refactoring in src/components/order-card/index.css:

src/components/order-card/index.css
@reference "../../app.css";

/* Use @utility to improve readability */
@utility order-card {
@apply block rounded-3xl bg-white shadow-lg shadow-slate-200/70 p-5 space-y-4;
}

@utility order-card__header {
@apply flex items-center justify-between gap-3;
}

@utility order-card__title {
@apply text-base font-semibold text-slate-900;
}

@utility order-card__meta {
@apply flex items-center justify-between text-sm text-slate-500;
}

@utility order-card__status {
@apply inline-flex items-center gap-1 rounded-full px-3 py-1 text-xs font-medium uppercase tracking-[0.28em];
}

/* Declare business status through @variant */
@custom-variant status-pending (&[data-status="pending"]);
@custom-variant status-finished (&[data-status="finished"]);
@custom-variant status-failed (&[data-status="failed"]);

.order-card__status {
@apply status-pending:bg-amber-100 status-pending:text-amber-600;
@apply status-finished:bg-emerald-100 status-finished:text-emerald-600;
@apply status-failed:bg-rose-100 status-failed:text-rose-600;
}

Key points:

  • Use @reference to let local style files inherit the themes and tools in the entry CSS
  • @utility makes the class name semantic while still continuing the @apply atomic class
  • @custom-variant (new in Tailwind 4) allows business status to be converted into semantic prefixes

Finally apply on the component instance:

src/pages/index/index.vue
<template>
<order-card
class="order-card"
data-status="pending"
title="Mini program exclusive package"
status-text="Pending payment"
created-at="2024-06-03"
amount="¥199"
>
<view class="flex items-center gap-2 rounded-2xl bg-slate-50 px-4 py-3">
<text class="text-xs font-medium text-slate-500"> automatically renews:</text>
<switch class="scale-90" :checked="false" />
</view>
</order-card>
</template>

2. Build reusable design tokens

Tailwind 4 abstracts themes into native CSS variables. You can maintain the token centrally in app.css and then output it through @theme:

src/app.css
@import "tailwindcss";

@theme {
--color-brand: oklch(66% 0.21 268);
--color-brand-muted: oklch(80% 0.04 268);
--radius-xl: 24px;
--shadow-elevated: 0 18px 40px -20px rgb(99 102 241 / 45%);
}

Then reference these variables directly in the business style, or combine Tailwind's bg-[...] writing method:

.order-card {
@apply shadow-[var(--shadow-elevated)];
}

.order-card__status {
@apply status-finished:bg-[var(--color-brand-muted)] status-finished:text-[var(--color-brand)];
}

Thanks to the CSS variable feature, you can also overwrite :root or the variables of the corresponding container on different pages to achieve theme switching.

3. Manage complex layout and responsiveness

Although the applet does not have width breakpoints in the traditional sense, we can still implement fault-tolerant layout with the help of media queries, min() / max() and other functions:

@layer utilities {
@responsive {
@media (min-width: 560px) {
.md\\:card-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: clamp(16px, 4vw, 36px);
}
}
}
}

Just match the default atomic class in the page:

<view class="space-y-4 md:card-grid">
<slot />
</view>

For cards that require horizontal scrolling, the snap-x, snap-mandatory, snap-center and other classes provided by Tailwind 4 are still applicable, and the processing logic of different ends is handed over to weapp-tailwindcss.

4. Multi-file collaboration and team agreement

When a project welcomes multi-person collaboration, it is recommended to follow the following conventions:

  1. Entry CSS only does aggregation: Centrally maintain @import, @source and @theme, and split the rest of the logic into independent files.
  2. Fixed index.css in the component directory: declare @utility and @apply in the component, and write them in the folder with the same name of the component for easy reference on demand.
  3. Public tool commission package: For example, src/styles/utilities/forms.css, internally declares all form-related @utility.
  4. lint and prompt configuration: Make sure that the team member's VS Code tailwindCSS.experimental.classRegex contains templates such as .wxml and .vue.

5. Debugging and performance tips

  • The compilation of Tailwind 4 follows the incremental mode, and the atomic classes generated at pnpm run:watch will be written to the cache. Delete .tailwind, node_modules/.cache/tailwind when a thorough cleanup is required.
  • The Mini Program Developer Tool does not support @layer. If you encounter coverage problems, you can enable the downgrade behavior of cssOptions.cssPresetEnv. For details, see [Advanced Edition] (/docs/quick-start/v4/tutorial/advanced).
  • With the help of pnpm dev:h5 (provided by some frameworks), you can quickly preview in the browser, and then return to the real machine for verification after debugging.

After completing this article, you should be able to apply Tailwind to actual business modules and form a set of reusable component writing methods. Next, we will focus on higher-level topics such as performance optimization, cross-end adaptation, and team collaboration.