Skip to content
WovenUI LogoWovenUI

Blocks

Card pattern

A content card with a title, a status badge, a short description and two actions.

Preview

Quarterly report

Ready

Revenue, churn and support volume for July to September, with a note from each team lead.

Live preview of the card, rendered from the HTML on this page.

HTML to copy

The markup of the preview, in WovenUI core utility classes. It needs only the prebuilt@wovenui/core/dist/wovenui.min.css, or your own build with $generate-utility-classes: true. No components package and no JavaScript.

HTML
<article class="bg-surface text-regular border rounded-lg shadow-sm hover:shadow-md transition-shadow p-6 max-w-sm">
    <div class="flex between x-center gap-3">
        <h3 class="text-lg font-semibold m-0">Quarterly report</h3>
        <span class="bg-success-subtle text-success text-xs font-medium rounded-full px-2 py-1">Ready</span>
    </div>
    <p class="text-muted mt-2 mb-0">Revenue, churn and support volume for July to September, with a note from each team lead.</p>
    <div class="flex wrap gap-2 mt-4">
        <button class="rounded-md" type="button">Open report</button>
        <button class="bg-alternate text-regular hover:bg-hover rounded-md" type="button">Download PDF</button>
    </div>
</article>

With apply()

The same result with BEM class names and no utility classes. @use "@wovenui/core" as *; emits the tokens and base styles, and each apply() writes one rule.

SCSS
@use "@wovenui/core" as *;

.card {
    @include apply(
        max-width(sm), // max width: the sm breakpoint, 640px
        p(6), // padding: spacing key 6 (1.5rem)
        bg(surface), // surface background, follows the theme
        text-color(regular), // regular text color, follows the theme
        border(1), // 1px border (width key 1), regular color
        rounded(lg), // corner radius: size key lg (0.75rem)
        shadow(sm), // small shadow (size key sm)
        transition-shadow, // animate box-shadow changes
        shadow(md) hover // medium shadow on hover, at every width
    );
}

.card__header {
    @include apply(
        flex, // display: flex
        between, // main axis: space between (justify-content)
        x-center, // cross axis: center (align-items)
        gap(3) // gap: spacing key 3 (0.75rem)
    );
}

.card__title {
    @include apply(
        m(0), // margin: 0
        font-size(lg), // font size key lg (1.25rem)
        font(semibold) // font weight: semibold (600)
    );
}

.card__badge {
    @include apply(
        px(2), // horizontal padding: spacing key 2 (0.5rem)
        py(1), // vertical padding: spacing key 1 (0.25rem)
        rounded(full), // fully rounded ends (pill shape)
        bg(success-subtle), // light success tint background
        text-color(success), // success text color
        font-size(xs), // font size key xs (0.75rem)
        font(medium) // font weight: medium (500)
    );
}

.card__text {
    @include apply(
        mt(2), // top margin: spacing key 2 (0.5rem)
        mb(0), // bottom margin: 0
        text-color(muted) // muted text color, follows the theme
    );
}

.card__actions {
    @include apply(
        flex, // display: flex
        wrap, // let items wrap onto new lines
        gap(2), // gap: spacing key 2 (0.5rem)
        mt(4) // top margin: spacing key 4 (1rem)
    );
}

.card__button {
    @include apply(rounded(md)); // corner radius: size key md (0.5rem)
}

.card__button--secondary {
    @include apply(
        bg(alternate), // alternate background, follows the theme
        text-color(regular), // regular text color, follows the theme
        bg(hover) hover // hover background on hover
    );
}
HTML
<article class="card">
    <div class="card__header">
        <h3 class="card__title">Quarterly report</h3>
        <span class="card__badge">Ready</span>
    </div>
    <p class="card__text">Revenue, churn and support volume for July to September, with a note from each team lead.</p>
    <div class="card__actions">
        <button class="card__button" type="button">Open report</button>
        <button class="card__button card__button--secondary" type="button">Download PDF</button>
    </div>
</article>

Tokens used

Every color comes from a theme token, so the pattern follows the light, dark and inverse themes with no extra CSS.

bg-surface, text-regular
Card background and text. Both flip together in dark mode.
border-regular
The edge drawn by border and border(1).
text-muted
The description, one step quieter than the title.
success-subtle, text-success
The badge: a tinted background with status text that keeps 4.5:1 contrast in both themes.
brand, brand-hover, text-on-brand
The primary button, styled by the base layer with a focus ring from border-focus.
bg-alternate, bg-hover
The secondary button at rest and on hover.
shadow-sm, shadow-md
Resting and hover elevation.