General
Card
Usage#
import { WdsCardComponent } from '@wds/angular/card';Examples#
Default#
import { Component } from '@angular/core';
import { WdsCardComponent } from '@wds/angular/card';
import { WdsButtonComponent } from '@wds/angular/button';
import { WdsFieldComponent, WdsFieldLabelComponent } from '@wds/angular/field';
import { WdsInputComponent } from '@wds/angular/input';
@Component({
selector: 'app-card-default-demo',
imports: [WdsCardComponent, WdsButtonComponent, WdsFieldComponent, WdsFieldLabelComponent, WdsInputComponent],
template: `
<wds-card class="w-full max-w-sm" heading="Login to your account" description="Enter your email below to login to your account">
<wds-button slot="action" variant="link" size="sm" href="#">Sign Up</wds-button>
<div class="grid gap-6">
<wds-field>
<wds-field-label>Email</wds-field-label>
<wds-input type="email" placeholder="[email protected]" required></wds-input>
</wds-field>
<wds-field>
<div class="flex items-center justify-between gap-4">
<wds-field-label>Password</wds-field-label>
<a class="text-(length:--wds-font-size-sm) text-inherit underline-offset-4" href="#">Forgot your password?</a>
</div>
<wds-input type="password" required></wds-input>
</wds-field>
</div>
<wds-button slot="footer" class="w-full [&::part(button)]:w-full">Login</wds-button>
<wds-button slot="footer" class="w-full [&::part(button)]:w-full" variant="outline">Login with Google</wds-button>
</wds-card>
`,
})
export class CardDefaultDemo {}Size#
size="sm" reduces the spacing and the title.
The small size fits dense views such as dashboards and lists.
import { Component } from '@angular/core';
import { WdsCardComponent } from '@wds/angular/card';
import { WdsButtonComponent } from '@wds/angular/button';
@Component({
selector: 'app-card-size-demo',
imports: [WdsCardComponent, WdsButtonComponent],
template: `
<wds-card class="w-full max-w-sm" size="sm" heading="Small Card" description="Smaller spacing and title.">
<p>The small size fits dense views such as dashboards and lists.</p>
<wds-button slot="footer" size="sm" variant="outline" class="w-full [&::part(button)]:w-full">Details</wds-button>
</wds-card>
`,
})
export class CardSizeDemo {}Image#
media slot shows an image across the full width at the top, in a 16:9 ratio by default (--wds-card-media-ratio).
Mountain hut stay, a local guide and transfers included.
import { Component } from '@angular/core';
import { WdsCardComponent } from '@wds/angular/card';
import { WdsBadgeComponent } from '@wds/angular/badge';
import { WdsButtonComponent } from '@wds/angular/button';
@Component({
selector: 'app-card-image-demo',
imports: [WdsCardComponent, WdsBadgeComponent, WdsButtonComponent],
template: `
<wds-card class="w-full max-w-sm" heading="Mountain Getaway" description="A 3-day weekend in the Alps">
<img
slot="media"
alt="Mountain landscape"
src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 160 90'%3E%3Cdefs%3E%3ClinearGradient id='s' x1='0' y1='0' x2='0' y2='1'%3E%3Cstop offset='0' stop-color='%2393c5fd'/%3E%3Cstop offset='1' stop-color='%23e0f2fe'/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width='160' height='90' fill='url(%23s)'/%3E%3Cpath d='M0 90 50 30l25 28 20-22 65 54z' fill='%23475569'/%3E%3Cpath d='M50 30 62 44 56 42 50 48 44 42z' fill='%23fff'/%3E%3C/svg%3E"
/>
<wds-badge slot="action" variant="secondary">New</wds-badge>
<p>Mountain hut stay, a local guide and transfers included.</p>
<wds-button slot="footer" class="w-full [&::part(button)]:w-full">Book now</wds-button>
</wds-card>
`,
})
export class CardImageDemo {}Dividers#
header-divider and footer-divider add lines around the content.
import { Component } from '@angular/core';
import { WdsCardComponent } from '@wds/angular/card';
import { WdsButtonComponent } from '@wds/angular/button';
import { WdsItemComponent, WdsItemGroupComponent } from '@wds/angular/item';
@Component({
selector: 'app-card-dividers-demo',
imports: [WdsCardComponent, WdsButtonComponent, WdsItemGroupComponent, WdsItemComponent],
template: `
<wds-card class="w-full max-w-sm" header-divider footer-divider heading="Notifications" description="You have 3 unread messages.">
<wds-button slot="action" variant="ghost" size="icon-sm" label="Notification settings">
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="1" /><circle cx="19" cy="12" r="1" /><circle cx="5" cy="12" r="1" /></svg>
</wds-button>
<wds-item-group>
<wds-item class="[&::part(item)]:px-0" size="sm" heading="Your order has been shipped" description="1 hour ago">
<span slot="media" class="size-2 rounded-full bg-chart-2"></span>
</wds-item>
<wds-item class="[&::part(item)]:px-0" size="sm" heading="New message from Anna" description="2 hours ago">
<span slot="media" class="size-2 rounded-full bg-chart-2"></span>
</wds-item>
<wds-item class="[&::part(item)]:px-0" size="sm" heading="Your subscription expires in 3 days" description="Yesterday">
<span slot="media" class="size-2 rounded-full bg-chart-2"></span>
</wds-item>
</wds-item-group>
<wds-button slot="footer" variant="outline" size="sm">Mark all as read</wds-button>
<wds-button slot="footer" size="sm" class="ms-auto">View all</wds-button>
</wds-card>
`,
})
export class CardDividersDemo {}Slots#
title and description slots replace the attributes, for example for formatted text.
import { Component } from '@angular/core';
import { WdsCardComponent } from '@wds/angular/card';
import { WdsBadgeComponent } from '@wds/angular/badge';
@Component({
selector: 'app-card-slots-demo',
imports: [WdsCardComponent, WdsBadgeComponent],
template: `
<div class="grid w-full max-w-2xl grid-cols-[repeat(auto-fill,minmax(16rem,1fr))] gap-4">
<wds-card>
<span slot="description">Total Revenue</span>
<span slot="title" class="text-[1.875rem] font-semibold tabular-nums">$1,250.00</span>
<wds-badge slot="action" variant="outline">+12.5%</wds-badge>
<span class="text-muted-foreground">Up from last month</span>
</wds-card>
<wds-card>
<span slot="description">New Customers</span>
<span slot="title" class="text-[1.875rem] font-semibold tabular-nums">1,234</span>
<wds-badge slot="action" variant="outline">−20%</wds-badge>
<span class="text-muted-foreground">Acquisition needs attention</span>
</wds-card>
</div>
`,
})
export class CardSlotsDemo {}Content only#
A card without a header and a footer: empty sections leave no gaps.
import { Component } from '@angular/core';
import { WdsCardComponent } from '@wds/angular/card';
@Component({
selector: 'app-card-content-only-demo',
imports: [WdsCardComponent],
template: `
<wds-card class="w-full max-w-sm">
<p>A card without a header and a footer: empty sections leave no gaps.</p>
</wds-card>
`,
})
export class CardContentOnlyDemo {}API References#
wds-card#
Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
| heading | string | '' | title slot takes precedence. |
| description | string | '' | description slot takes precedence. |
| heading-level.headingLevel | number | 3 | aria-level). |
| size | WdsCardSize | 'default' | sm reduces the spacing and the title. |
| header-divider.headerDivider | boolean | false | |
| footer-divider.footerDivider | boolean | false |
Slots
| Slot | Description |
|---|---|
| (default) | |
| media | |
| title | heading). |
| description | description). |
| action | |
| footer |
CSS parts (::part)
| Part | Description |
|---|---|
| card | |
| media | |
| header | |
| title | |
| description | |
| action | |
| content | |
| footer |
CSS custom properties
| Property | Description |
|---|---|
| --wds-card-padding | sm). |
| --wds-card-gap | |
| --wds-card-radius | |
| --wds-card-background | |
| --wds-card-border | |
| --wds-card-title-size | |
| --wds-card-media-ratio | media slot (default 16 / 9). |
Accessibility#
Screen reader#
role="heading" with aria-level from heading-level (default 3). Set the level that fits the outline of the page.
<section> or <article> with an accessible name.
media slot an alt that describes it, or alt="" when it is decorative. An icon-only button in the action slot needs a label.