Skip to content
NuvoUI

Card

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.

With utility classes

The markup of the preview. Classes come from the prebuilt dist/nuvoui.min.css, or from your own build with $generate-utility-classes: true.

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 "@nuvoui/core" as *; emits the tokens and base styles, and each apply() writes one rule.

SCSS
@use "@nuvoui/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 recipe 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.