Card
This library is a work-in-progress. We are releasing it early to gather feedback, but it is not ready for production.
Card is a versatile container for grouping related content and actions. It provides a clean, visual structure for organizing information and can be customized with shadows, animations, color variants, and more.
Examples
Live Preview
Default Card
This is a basic card with default styling.
Card with Header
Product Details
This card demonstrates using the header slot to add a title section with visual separation.
Shadow Card
Card with Shadow
Hover over this card to see the enhanced shadow effect.
Animated Card with Footer
Animated Card
Hover to see smooth animation (translateY with shadow enhancement).
Rounded Card Variants
Cards can have different border radius sizes: small, medium, or large.
Small Rounded (sm)
Subtle rounded corners using --ag-radius-sm (0.25rem).
Medium Rounded (md)
Moderate rounded corners using --ag-radius-md (0.375rem).
Large Rounded (lg)
Prominent rounded corners using --ag-radius-lg (1rem).
Stacked Content
Stacked Content
First paragraph with automatic margin.
Second paragraph with automatic margin.
Third paragraph with automatic margin.
Variant Cards
Success
Operation completed successfully!
Information
Here's some helpful information for you.
Error
Something went wrong. Please try again.
Warning
Please review this information carefully.
Monochrome
Clean and modern monochrome design.
Card with Slots (Header and Footer)
Card Header
Main Content
This card demonstrates the header, default, and footer slots.
Combined Features
Premium Card
This card combines multiple features: shadow, animation, rounded corners, and success variant.
Hover to see the smooth animation effect!
Card Gallery
Card 1
Standard card with header, shadow and animation.
Card 2
Success variant with shadow and animation.
Card 3
Info variant with header, shadow and animation.
Card 4
Error variant with shadow and animation.
Card 5
Warning variant with header.
Card 6
Rounded corners with shadow and animation.
Media Card (Top)
Use :has-media="true" with media-position="top" for edge-to-edge media above the card content.
Mountain Retreat
A breathtaking mountain landscape captured at golden hour.
Media Card (Bottom)
Use media-position="bottom" to render media below the card content.
Mountain Retreat
A breathtaking mountain landscape captured at golden hour.
Customized with CSS Shadow Parts
Customized with CSS Parts
This card demonstrates CSS Shadow Parts customization.
The wrapper, header, content, and footer are styled using ::part() selectors.
View Vue Code
<template>
<section>
<div class="mbe4">
<h2>Default Card</h2>
</div>
<div class="stacked-mobile">
<VueCard>
<p>This is a basic card with default styling.</p>
</VueCard>
</div>
<div class="mbe4">
<h2>Card with Header</h2>
</div>
<div class="stacked-mobile">
<VueCard :shadow="true">
<template #header>
<h3 class="m0">Product Details</h3>
</template>
<p>This card demonstrates using the header slot to add a title section with visual separation.</p>
</VueCard>
</div>
<div class="mbe4">
<h2>Shadow Card</h2>
</div>
<div class="stacked-mobile">
<VueCard :shadow="true">
<h3 class="m0">Card with Shadow</h3>
<p>Hover over this card to see the enhanced shadow effect.</p>
</VueCard>
</div>
<div class="mbe4">
<h2>Animated Card with Footer</h2>
</div>
<div class="stacked-mobile">
<VueCard
:shadow="true"
:animated="true"
>
<template #header>
<h3 class="m0">Animated Card</h3>
</template>
<p>Hover to see smooth animation (translateY with shadow enhancement).</p>
<template #footer>
<div style="display: flex; gap: 0.5rem; justify-content: flex-end;">
<VueButton>View Details</VueButton>
</div>
</template>
</VueCard>
</div>
<div class="mbe4">
<h2>Rounded Card Variants</h2>
<p class="mbs2 mbe3">Cards can have different border radius sizes: small, medium, or large.</p>
</div>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 1rem;">
<VueCard rounded="sm">
<h3 class="m0">Small Rounded (sm)</h3>
<p>Subtle rounded corners using --ag-radius-sm (0.25rem).</p>
</VueCard>
<VueCard rounded="md">
<h3 class="m0">Medium Rounded (md)</h3>
<p>Moderate rounded corners using --ag-radius-md (0.375rem).</p>
</VueCard>
<VueCard rounded="lg">
<h3 class="m0">Large Rounded (lg)</h3>
<p>Prominent rounded corners using --ag-radius-lg (1rem).</p>
</VueCard>
</div>
<div class="mbe4">
<h2>Stacked Content</h2>
</div>
<div class="stacked-mobile">
<VueCard :stacked="true">
<h3 class="m0">Stacked Content</h3>
<p>First paragraph with automatic margin.</p>
<p>Second paragraph with automatic margin.</p>
<p>Third paragraph with automatic margin.</p>
</VueCard>
</div>
<div class="mbe4">
<h2>Variant Cards</h2>
</div>
<div class="stacked">
<VueCard
variant="success"
class="mbe2"
>
<h3 class="m0">Success</h3>
<p>Operation completed successfully!</p>
</VueCard>
<VueCard
variant="info"
class="mbe2"
>
<h3 class="m0">Information</h3>
<p>Here's some helpful information for you.</p>
</VueCard>
<VueCard
variant="error"
class="mbe2"
>
<h3 class="m0">Error</h3>
<p>Something went wrong. Please try again.</p>
</VueCard>
<VueCard
variant="warning"
class="mbe2"
>
<h3 class="m0">Warning</h3>
<p>Please review this information carefully.</p>
</VueCard>
<VueCard
variant="monochrome"
class="mbe2"
>
<h3 class="m0">Monochrome</h3>
<p>Clean and modern monochrome design.</p>
</VueCard>
</div>
<div class="mbe4">
<h2>Card with Slots (Header and Footer)</h2>
</div>
<div class="stacked-mobile">
<VueCard :shadow="true">
<template #header>
<h3 class="m0">Card Header</h3>
</template>
<div>
<h4>Main Content</h4>
<p>This card demonstrates the header, default, and footer slots.</p>
</div>
<template #footer>
<VueButton variant="secondary">Cancel</VueButton>
<VueButton
variant="primary"
style="margin-left: 0.5rem;"
>
Confirm
</VueButton>
</template>
</VueCard>
</div>
<div class="mbe4">
<h2>Combined Features</h2>
</div>
<div class="stacked-mobile">
<VueCard
:shadow="true"
:animated="true"
rounded="md"
variant="success"
>
<h3 class="m0">Premium Card</h3>
<p>This card combines multiple features: shadow, animation, rounded corners, and success variant.</p>
<p>Hover to see the smooth animation effect!</p>
</VueCard>
</div>
<div class="mbe4">
<h2>Card Gallery</h2>
</div>
<div style="display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 1.5rem;">
<VueCard
:shadow="true"
:animated="true"
>
<template #header>
<h3>Card 1</h3>
</template>
<p>Standard card with header, shadow and animation.</p>
</VueCard>
<VueCard
:shadow="true"
:animated="true"
variant="success"
>
<h4>Card 2</h4>
<p>Success variant with shadow and animation.</p>
</VueCard>
<VueCard
:shadow="true"
:animated="true"
variant="info"
>
<template #header>
<h4>Card 3</h4>
</template>
<p>Info variant with header, shadow and animation.</p>
<template #footer>
<VueButton
variant="monochrome"
:bordered="true"
>Learn More</VueButton>
</template>
</VueCard>
<VueCard
:shadow="true"
:animated="true"
variant="error"
>
<h4>Card 4</h4>
<p>Error variant with shadow and animation.</p>
</VueCard>
<VueCard
:shadow="true"
:animated="true"
variant="warning"
>
<template #header>
<h4>Card 5</h4>
</template>
<p>Warning variant with header.</p>
</VueCard>
<VueCard
:shadow="true"
:animated="true"
rounded="md"
>
<h4>Card 6</h4>
<p>Rounded corners with shadow and animation.</p>
<template #footer>
<VueButton variant="success">Action</VueButton>
</template>
</VueCard>
</div>
<div class="mbe4">
<h2>Media Card (Top)</h2>
<p class="mbs2 mbe3">Use <code>:has-media="true"</code> with <code>media-position="top"</code> for edge-to-edge media above the card content.</p>
</div>
<div class="stacked-mobile">
<VueCard :has-media="true" media-position="top" rounded="md" :shadow="true" style="max-width: 400px;">
<template #media>
<img
src="https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=800&auto=format&fit=crop"
alt="Mountain landscape"
/>
</template>
<template #header>
<h3 class="m0">Mountain Retreat</h3>
</template>
<p>A breathtaking mountain landscape captured at golden hour.</p>
<template #footer>
<VueButton>View Gallery</VueButton>
</template>
</VueCard>
</div>
<div class="mbe4">
<h2>Media Card (Bottom)</h2>
<p class="mbs2 mbe3">Use <code>media-position="bottom"</code> to render media below the card content.</p>
</div>
<div class="stacked-mobile">
<VueCard :has-media="true" media-position="bottom" rounded="md" :shadow="true" style="max-width: 400px;">
<template #header>
<h3 class="m0">Mountain Retreat</h3>
</template>
<p>A breathtaking mountain landscape captured at golden hour.</p>
<template #media>
<img
src="https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=800&auto=format&fit=crop"
alt="Mountain landscape"
/>
</template>
</VueCard>
</div>
<div class="mbe4">
<h2>Customized with CSS Shadow Parts</h2>
</div>
<div class="stacked-mobile">
<VueCard
:shadow="true"
class="custom-parts-card"
>
<template #header>
<h3 style="margin: 0; color: white;">Customized with CSS Parts</h3>
</template>
<p>This card demonstrates CSS Shadow Parts customization.</p>
<p>The wrapper, header, content, and footer are styled using ::part() selectors.</p>
<template #footer>
<VueButton
variant="monochrome"
shape="rounded"
>
Learn More
</VueButton>
</template>
</VueCard>
</div>
</section>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import { VueCard } from "agnosticui-core/card/vue";
import VueButton from "agnosticui-core/button/vue";
export default defineComponent({
name: "CardExamples",
components: {
VueButton,
VueCard,
},
});
</script>
<style scoped>
.custom-parts-card::part(ag-card-wrapper) {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.custom-parts-card::part(ag-card-header) {
border-bottom: 2px solid rgba(255, 255, 255, 0.3);
padding-bottom: 1rem;
margin-bottom: 1rem;
}
.custom-parts-card::part(ag-card-content) {
color: white;
font-size: 1.1rem;
}
.custom-parts-card::part(ag-card-footer) {
border-top: 2px solid rgba(255, 255, 255, 0.3);
padding-top: 1rem;
margin-top: 1rem;
}
</style>
Live Preview
View Lit / Web Component Code
import { LitElement, html } from 'lit';
import 'agnosticui-core/card';
import 'agnosticui-core/button';
export class CardLitExamples extends LitElement {
// Render in light DOM to access global utility classes
createRenderRoot() {
return this;
}
render() {
return html`
<section>
<!-- Default Card -->
<div class="mbe4">
<h2>Default Card</h2>
</div>
<div class="stacked-mobile">
<ag-card>
<p>This is a basic card with default styling.</p>
</ag-card>
</div>
<!-- Card with Header -->
<div class="mbe4">
<h2>Card with Header</h2>
</div>
<div class="stacked-mobile">
<ag-card shadow>
<h3 slot="header" class="m0">Product Details</h3>
<p>This card demonstrates using the header slot to add a title section with visual separation.</p>
</ag-card>
</div>
<!-- Shadow Card -->
<div class="mbe4">
<h2>Shadow Card</h2>
</div>
<div class="stacked-mobile">
<ag-card shadow>
<h3 class="m0">Card with Shadow</h3>
<p>Hover over this card to see the enhanced shadow effect.</p>
</ag-card>
</div>
<!-- Animated Card with Footer -->
<div class="mbe4">
<h2>Animated Card with Footer</h2>
</div>
<div class="stacked-mobile">
<ag-card shadow animated>
<h3 slot="header" class="m0">Animated Card</h3>
<p>Hover to see smooth animation (translateY with shadow enhancement).</p>
<div slot="footer" style="display: flex; gap: 0.5rem; justify-content: flex-end;">
<ag-button>View Details</ag-button>
</div>
</ag-card>
</div>
<!-- Rounded Card Variants -->
<div class="mbe4">
<h2>Rounded Card Variants</h2>
<p class="mbs2 mbe3">Cards can have different border radius sizes: small, medium, or large.</p>
</div>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 1rem;">
<ag-card rounded="sm">
<h3 class="m0">Small Rounded (sm)</h3>
<p>Subtle rounded corners using --ag-radius-sm (0.25rem).</p>
</ag-card>
<ag-card rounded="md">
<h3 class="m0">Medium Rounded (md)</h3>
<p>Moderate rounded corners using --ag-radius-md (0.375rem).</p>
</ag-card>
<ag-card rounded="lg">
<h3 class="m0">Large Rounded (lg)</h3>
<p>Prominent rounded corners using --ag-radius-lg (1rem).</p>
</ag-card>
</div>
<!-- Stacked Content -->
<div class="mbe4">
<h2>Stacked Content</h2>
</div>
<div class="stacked-mobile">
<ag-card stacked>
<h3 class="m0">Stacked Content</h3>
<p>First paragraph with automatic margin.</p>
<p>Second paragraph with automatic margin.</p>
<p>Third paragraph with automatic margin.</p>
</ag-card>
</div>
<!-- Variant Cards -->
<div class="mbe4">
<h2>Variant Cards</h2>
</div>
<div class="stacked">
<ag-card variant="success" class="mbe2">
<h3 class="m0">Success</h3>
<p>Operation completed successfully!</p>
</ag-card>
<ag-card variant="info" class="mbe2">
<h3 class="m0">Information</h3>
<p>Here's some helpful information for you.</p>
</ag-card>
<ag-card variant="error" class="mbe2">
<h3 class="m0">Error</h3>
<p>Something went wrong. Please try again.</p>
</ag-card>
<ag-card variant="warning" class="mbe2">
<h3 class="m0">Warning</h3>
<p>Please review this information carefully.</p>
</ag-card>
<ag-card variant="monochrome" class="mbe2">
<h3 class="m0">Monochrome</h3>
<p>Clean and modern monochrome design.</p>
</ag-card>
</div>
<!-- Card with Slots (Header and Footer) -->
<div class="mbe4">
<h2>Card with Slots (Header and Footer)</h2>
</div>
<div class="stacked-mobile">
<ag-card shadow>
<h3 slot="header" class="m0">Card Header</h3>
<div>
<h4>Main Content</h4>
<p>This card demonstrates the header, default, and footer slots.</p>
</div>
<div slot="footer">
<ag-button variant="secondary">Cancel</ag-button>
<ag-button variant="primary" style="margin-left: 0.5rem;">Confirm</ag-button>
</div>
</ag-card>
</div>
<!-- Combined Features -->
<div class="mbe4">
<h2>Combined Features</h2>
</div>
<div class="stacked-mobile">
<ag-card shadow animated rounded="md" variant="success">
<h3 class="m0">Premium Card</h3>
<p>This card combines multiple features: shadow, animation, rounded corners, and success variant.</p>
<p>Hover to see the smooth animation effect!</p>
</ag-card>
</div>
<!-- Card Gallery -->
<div class="mbe4">
<h2>Card Gallery</h2>
</div>
<div style="display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 1.5rem;">
<ag-card shadow animated>
<h3 slot="header">Card 1</h3>
<p>Standard card with header, shadow and animation.</p>
</ag-card>
<ag-card shadow animated variant="success">
<h4>Card 2</h4>
<p>Success variant with shadow and animation.</p>
</ag-card>
<ag-card shadow animated variant="info">
<h4 slot="header">Card 3</h4>
<p>Info variant with header, shadow and animation.</p>
<ag-button slot="footer" variant="monochrome" bordered>Learn More</ag-button>
</ag-card>
<ag-card shadow animated variant="error">
<h4>Card 4</h4>
<p>Error variant with shadow and animation.</p>
</ag-card>
<ag-card shadow animated variant="warning">
<h4 slot="header">Card 5</h4>
<p>Warning variant with header.</p>
</ag-card>
<ag-card shadow animated rounded="md">
<h4>Card 6</h4>
<p>Rounded corners with shadow and animation.</p>
<ag-button slot="footer" variant="success">Action</ag-button>
</ag-card>
</div>
<!-- Media Card — Top -->
<div class="mbe4">
<h2>Media Card (Top)</h2>
<p class="mbs2 mbe3">Use the <code>has-media</code> attribute with <code>media-position="top"</code> for edge-to-edge media above the card content.</p>
</div>
<div class="stacked-mobile">
<ag-card has-media media-position="top" rounded="md" shadow style="max-width: 400px;">
<img
slot="media"
src="https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=800&auto=format&fit=crop"
alt="Mountain landscape"
/>
<h3 slot="header" class="m0">Mountain Retreat</h3>
<p>A breathtaking mountain landscape captured at golden hour.</p>
<div slot="footer">
<ag-button>View Gallery</ag-button>
</div>
</ag-card>
</div>
<!-- Media Card — Bottom -->
<div class="mbe4">
<h2>Media Card (Bottom)</h2>
<p class="mbs2 mbe3">Use <code>media-position="bottom"</code> to render media below the card content.</p>
</div>
<div class="stacked-mobile">
<ag-card has-media media-position="bottom" rounded="md" shadow style="max-width: 400px;">
<h3 slot="header" class="m0">Mountain Retreat</h3>
<p>A breathtaking mountain landscape captured at golden hour.</p>
<img
slot="media"
src="https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=800&auto=format&fit=crop"
alt="Mountain landscape"
/>
</ag-card>
</div>
<!-- Customized with CSS Shadow Parts -->
<div class="mbe4">
<h2>Customized with CSS Shadow Parts</h2>
</div>
<div class="stacked-mobile">
<ag-card shadow class="custom-parts-card">
<h3 slot="header" style="margin: 0; color: white;">Customized with CSS Parts</h3>
<p>This card demonstrates CSS Shadow Parts customization.</p>
<p>The wrapper, header, content, and footer are styled using ::part() selectors.</p>
<ag-button slot="footer" variant="monochrome" shape="rounded">Learn More</ag-button>
</ag-card>
</div>
</section>
`;
}
}
// Register the custom element
customElements.define('card-lit-examples', CardLitExamples);
Interactive Preview: Click the "Open in StackBlitz" button below to see this example running live in an interactive playground.
View React Code
import { ReactCard } from "agnosticui-core/card/react";
import { ReactButton } from "agnosticui-core/button/react";
export default function CardReactExamples() {
return (
<section>
{/* Default Card */}
<div className="mbe4">
<h2>Default Card</h2>
</div>
<div className="stacked-mobile">
<ReactCard>
<p>This is a basic card with default styling.</p>
</ReactCard>
</div>
{/* Card with Header */}
<div className="mbe4">
<h2>Card with Header</h2>
</div>
<div className="stacked-mobile">
<ReactCard shadow>
<h3 slot="header" className="m0">Product Details</h3>
<p>This card demonstrates using the header slot to add a title section with visual separation.</p>
</ReactCard>
</div>
{/* Shadow Card */}
<div className="mbe4">
<h2>Shadow Card</h2>
</div>
<div className="stacked-mobile">
<ReactCard shadow>
<h3 className="m0">Card with Shadow</h3>
<p>Hover over this card to see the enhanced shadow effect.</p>
</ReactCard>
</div>
{/* Animated Card with Footer */}
<div className="mbe4">
<h2>Animated Card with Footer</h2>
</div>
<div className="stacked-mobile">
<ReactCard shadow animated>
<h3 slot="header" className="m0">Animated Card</h3>
<p>Hover to see smooth animation (translateY with shadow enhancement).</p>
<div slot="footer" style={{ display: "flex", gap: "0.5rem", justifyContent: "flex-end" }}>
<ReactButton>View Details</ReactButton>
</div>
</ReactCard>
</div>
{/* Rounded Card Variants */}
<div className="mbe4">
<h2>Rounded Card Variants</h2>
<p className="mbs2 mbe3">Cards can have different border radius sizes: small, medium, or large.</p>
</div>
<div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(250px, 1fr))", gap: "1rem" }}>
<ReactCard rounded="sm">
<h3 className="m0">Small Rounded (sm)</h3>
<p>Subtle rounded corners using --ag-radius-sm (0.25rem).</p>
</ReactCard>
<ReactCard rounded="md">
<h3 className="m0">Medium Rounded (md)</h3>
<p>Moderate rounded corners using --ag-radius-md (0.375rem).</p>
</ReactCard>
<ReactCard rounded="lg">
<h3 className="m0">Large Rounded (lg)</h3>
<p>Prominent rounded corners using --ag-radius-lg (1rem).</p>
</ReactCard>
</div>
{/* Stacked Content */}
<div className="mbe4">
<h2>Stacked Content</h2>
</div>
<div className="stacked-mobile">
<ReactCard stacked>
<h3 className="m0">Stacked Content</h3>
<p>First paragraph with automatic margin.</p>
<p>Second paragraph with automatic margin.</p>
<p>Third paragraph with automatic margin.</p>
</ReactCard>
</div>
{/* Variant Cards */}
<div className="mbe4">
<h2>Variant Cards</h2>
</div>
<div className="stacked">
<ReactCard variant="success" className="mbe2">
<h3 className="m0">Success</h3>
<p>Operation completed successfully!</p>
</ReactCard>
<ReactCard variant="info" className="mbe2">
<h3 className="m0">Information</h3>
<p>Here's some helpful information for you.</p>
</ReactCard>
<ReactCard variant="error" className="mbe2">
<h3 className="m0">Error</h3>
<p>Something went wrong. Please try again.</p>
</ReactCard>
<ReactCard variant="warning" className="mbe2">
<h3 className="m0">Warning</h3>
<p>Please review this information carefully.</p>
</ReactCard>
<ReactCard variant="monochrome" className="mbe2">
<h3 className="m0">Monochrome</h3>
<p>Clean and modern monochrome design.</p>
</ReactCard>
</div>
{/* Card with Slots (Header and Footer) */}
<div className="mbe4">
<h2>Card with Slots (Header and Footer)</h2>
</div>
<div className="stacked-mobile">
<ReactCard shadow>
<h3 slot="header" className="m0">Card Header</h3>
<div>
<h4>Main Content</h4>
<p>This card demonstrates the header, default, and footer slots.</p>
</div>
<div slot="footer">
<ReactButton variant="secondary">Cancel</ReactButton>
<ReactButton variant="primary" style={{ marginLeft: "0.5rem" }}>
Confirm
</ReactButton>
</div>
</ReactCard>
</div>
{/* Combined Features */}
<div className="mbe4">
<h2>Combined Features</h2>
</div>
<div className="stacked-mobile">
<ReactCard shadow animated rounded="md" variant="success">
<h3 className="m0">Premium Card</h3>
<p>This card combines multiple features: shadow, animation, rounded corners, and success variant.</p>
<p>Hover to see the smooth animation effect!</p>
</ReactCard>
</div>
{/* Card Gallery */}
<div className="mbe4">
<h2>Card Gallery</h2>
</div>
<div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(280px, 1fr))", gap: "1.5rem" }}>
<ReactCard shadow animated>
<h3 slot="header">Card 1</h3>
<p>Standard card with header, shadow and animation.</p>
</ReactCard>
<ReactCard shadow animated variant="success">
<h4>Card 2</h4>
<p>Success variant with shadow and animation.</p>
</ReactCard>
<ReactCard shadow animated variant="info">
<h4 slot="header">Card 3</h4>
<p>Info variant with header, shadow and animation.</p>
<ReactButton slot="footer" variant="monochrome" bordered>
Learn More
</ReactButton>
</ReactCard>
<ReactCard shadow animated variant="error">
<h4>Card 4</h4>
<p>Error variant with shadow and animation.</p>
</ReactCard>
<ReactCard shadow animated variant="warning">
<h4 slot="header">Card 5</h4>
<p>Warning variant with header.</p>
</ReactCard>
<ReactCard shadow animated rounded="md">
<h4>Card 6</h4>
<p>Rounded corners with shadow and animation.</p>
<ReactButton slot="footer" variant="success">
Action
</ReactButton>
</ReactCard>
</div>
{/* Media Card — Top */}
<div className="mbe4">
<h2>Media Card (Top)</h2>
<p className="mbs2 mbe3">
Use <code>hasMedia</code> with <code>mediaPosition="top"</code> for edge-to-edge media above the card content.
</p>
</div>
<div className="stacked-mobile">
<ReactCard hasMedia mediaPosition="top" rounded="md" shadow style={{ maxWidth: "400px" }}>
<img
slot="media"
src="https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=800&auto=format&fit=crop"
alt="Mountain landscape"
/>
<h3 slot="header" className="m0">Mountain Retreat</h3>
<p>A breathtaking mountain landscape captured at golden hour.</p>
<div slot="footer">
<ReactButton>View Gallery</ReactButton>
</div>
</ReactCard>
</div>
{/* Media Card — Bottom */}
<div className="mbe4">
<h2>Media Card (Bottom)</h2>
<p className="mbs2 mbe3">
Use <code>mediaPosition="bottom"</code> to render media below the card content.
</p>
</div>
<div className="stacked-mobile">
<ReactCard hasMedia mediaPosition="bottom" rounded="md" shadow style={{ maxWidth: "400px" }}>
<h3 slot="header" className="m0">Mountain Retreat</h3>
<p>A breathtaking mountain landscape captured at golden hour.</p>
<img
slot="media"
src="https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=800&auto=format&fit=crop"
alt="Mountain landscape"
/>
</ReactCard>
</div>
{/* Customized with CSS Shadow Parts */}
<div className="mbe4">
<h2>Customized with CSS Shadow Parts</h2>
</div>
<div className="stacked-mobile">
<ReactCard shadow className="custom-parts-card">
<h3 slot="header" style={{ margin: 0, color: "white" }}>
Customized with CSS Parts
</h3>
<p>This card demonstrates CSS Shadow Parts customization.</p>
<p>The wrapper, header, content, and footer are styled using ::part() selectors.</p>
<ReactButton slot="footer" variant="monochrome" shape="rounded">
Learn More
</ReactButton>
</ReactCard>
</div>
</section>
);
}
Usage
TIP
The framework examples below import AgnosticUI as an npm package. Alternatively, you can use the CLI for complete control, AI/LLM visibility, and full code ownership:
npx ag init --framework FRAMEWORK # react, vue, lit, svelte, etc.
npx ag add CardThe CLI copies source code directly into your project, giving you full visibility and control. After running npx ag add, you'll receive exact import instructions.
Vue
<template>
<section>
<VueCard>
<h3>Card Title</h3>
<p>Basic card content with default styling.</p>
</VueCard>
<VueCard :shadow="true" :animated="true">
<h3>Animated Card</h3>
<p>Hover to see the animation effect.</p>
</VueCard>
<VueCard variant="success">
<h3>Success</h3>
<p>Operation completed successfully!</p>
</VueCard>
<VueCard :shadow="true">
<template #header>
<h4 style="margin: 0;">Header Slot</h4>
</template>
<div>
<p>Main content goes here.</p>
</div>
<template #footer>
<VueButton variant="primary" shape="rounded">Action</VueButton>
</template>
</VueCard>
<VueCard :has-media="true" media-position="top" rounded="md" :shadow="true">
<template #media>
<img src="https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=800&auto=format&fit=crop" alt="Mountain landscape" />
</template>
<template #header>
<h4 style="margin: 0;">Media Card</h4>
</template>
<p>Edge-to-edge image with rounded corners.</p>
</VueCard>
</section>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import { VueCard } from "agnosticui-core/card/vue";
import { VueButton } from "agnosticui-core/button/vue";
export default defineComponent({
components: { VueCard, VueButton },
});
</script>React
import { ReactCard } from "agnosticui-core/card/react";
import { ReactButton } from "agnosticui-core/button/react";
export default function CardExamples() {
return (
<section>
<ReactCard>
<h3>Card Title</h3>
<p>Basic card content with default styling.</p>
</ReactCard>
<ReactCard shadow animated>
<h3>Animated Card</h3>
<p>Hover to see the animation effect.</p>
</ReactCard>
<ReactCard variant="success">
<h3>Success</h3>
<p>Operation completed successfully!</p>
</ReactCard>
<ReactCard shadow>
<h3 slot="header" style={{ margin: 0 }}>
Header Slot
</h3>
<div>
<p>Main content goes here.</p>
</div>
<ReactButton variant="primary" shape="rounded" slot="footer">
Action
</ReactButton>
</ReactCard>
<ReactCard hasMedia mediaPosition="top" rounded="md" shadow>
<img
slot="media"
src="https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=800&auto=format&fit=crop"
alt="Mountain landscape"
/>
<h3 slot="header" style={{ margin: 0 }}>Media Card</h3>
<p>Edge-to-edge image with rounded corners.</p>
</ReactCard>
</section>
);
}Lit (Web Components)
<script type="module">
import "agnosticui-core/card";
import "agnosticui-core/button";
</script>
<ag-card>
<h3>Card Title</h3>
<p>Basic card content with default styling.</p>
</ag-card>
<ag-card shadow animated>
<h3>Animated Card</h3>
<p>Hover to see the animation effect.</p>
</ag-card>
<ag-card variant="success">
<h3>Success</h3>
<p>Operation completed successfully!</p>
</ag-card>
<ag-card shadow>
<h4 slot="header" style="margin: 0;">Header Slot</h4>
<div>
<p>Main content goes here.</p>
</div>
<ag-button variant="primary" shape="rounded" slot="footer">Action</ag-button>
</ag-card>
<ag-card has-media media-position="top" rounded="md" shadow>
<img slot="media" src="https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=800&auto=format&fit=crop" alt="Mountain landscape" />
<h4 slot="header" style="margin: 0;">Media Card</h4>
<p>Edge-to-edge image with rounded corners.</p>
</ag-card>Props
| Prop | Type | Default | Description |
|---|---|---|---|
stacked | boolean | false | Applies vertical spacing between slotted children |
shadow | boolean | false | Adds box-shadow with enhanced hover effect |
animated | boolean | false | Enables smooth transitions on hover (translateY + shadow) |
rounded | 'sm' | 'md' | 'lg' | boolean | '' | Border radius size. Use true for default 'md' or specify 'sm'/'lg' |
variant | 'success' | 'info' | 'error' | 'warning' | '' | '' | Color variant for semantic meaning |
hasMedia | boolean | false | Enables the media slot for edge-to-edge image/video rendering |
mediaPosition | 'top' | 'bottom' | 'top' | Whether media renders above or below the header/content/footer |
Slots
| Slot | Description |
|---|---|
media | Edge-to-edge media content (image/video). Requires hasMedia to be true |
header | Optional header content displayed at the top of the card |
default | Main content of the card |
footer | Optional footer content displayed at the bottom of the card |
CSS Shadow Parts
Shadow Parts allow you to style internal elements of the card from outside the shadow DOM using the ::part() CSS selector.
| Part | Description |
|---|---|
ag-card-wrapper | The main wrapper element that contains all card content |
ag-card-media | The media wrapper (present when hasMedia is true) |
ag-card-header | The header section wrapper (even when empty) |
ag-card-content | The main content section wrapper |
ag-card-footer | The footer section wrapper (even when empty) |
Customization Example
ag-card::part(ag-card-wrapper) {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
padding: 2rem;
}
ag-card::part(ag-card-header) {
border-bottom: 2px solid rgba(255, 255, 255, 0.3);
padding-bottom: 1rem;
}
ag-card::part(ag-card-content) {
color: white;
font-size: 1.1rem;
}
ag-card::part(ag-card-footer) {
border-top: 2px solid rgba(255, 255, 255, 0.3);
padding-top: 1rem;
}Design Patterns
Basic Content Card
Use for grouping related information with a simple border and background:
<VueCard>
<h3>Product Title</h3>
<p>Product description goes here.</p>
<span>$49.99</span>
</VueCard>Interactive Card with Hover Effects
Combine shadow and animation for engaging hover interactions:
<VueCard :shadow="true" :animated="true">
<h3>Featured Item</h3>
<p>Hover to see the lift effect.</p>
</VueCard>Semantic Cards with Variants
Use variant colors to convey status or context:
<VueCard variant="success">
<h3>Payment Successful</h3>
<p>Your order has been confirmed.</p>
</VueCard>Structured Card with Slots
Use slots for clearly separated header/footer sections. The header and footer automatically get appropriate styling (borders, padding) and are hidden when empty:
<VueCard :shadow="true">
<template #header>
<h3 style="margin: 0;">Settings</h3>
</template>
<p>Configure your preferences</p>
<template #footer>
<div style="display: flex; gap: 0.5rem; justify-content: flex-end;">
<button>Cancel</button>
<button>Save</button>
</div>
</template>
</VueCard>
<VueCard :shadow="true">
<template #header>
<h3 style="margin: 0;">Product Details</h3>
</template>
<p>Product information and description...</p>
</VueCard>
<VueCard>
<p>Review the information below</p>
<template #footer>
<button>Learn More</button>
</template>
</VueCard>Media Card
Use hasMedia with the media slot to render images or video edge-to-edge inside the card. The media wrapper has no padding — it bleeds to the card's edges. Combined with rounded, the image corners clip correctly via overflow: hidden.
<!-- Media at the top (default) -->
<VueCard :has-media="true" media-position="top" rounded="md" :shadow="true">
<template #media>
<img src="https://images.unsplash.com/photo-..." alt="Descriptive alt text" />
</template>
<template #header>
<h3 style="margin: 0;">Card Title</h3>
</template>
<p>Card body content goes here.</p>
<template #footer>
<VueButton>View Details</VueButton>
</template>
</VueCard>
<!-- Media at the bottom -->
<VueCard :has-media="true" media-position="bottom" rounded="md">
<template #header>
<h3 style="margin: 0;">Card Title</h3>
</template>
<p>Card body content goes here.</p>
<template #media>
<img src="https://images.unsplash.com/photo-..." alt="Descriptive alt text" />
</template>
</VueCard>In Lit (Web Components):
<ag-card has-media media-position="top" rounded="md" shadow>
<img slot="media" src="https://images.unsplash.com/photo-..." alt="Descriptive alt text" />
<h3 slot="header" style="margin: 0;">Card Title</h3>
<p>Card body content goes here.</p>
<ag-button slot="footer">View Details</ag-button>
</ag-card>Accessibility
Always provide a meaningful alt attribute on <img> elements slotted into media. If the image is purely decorative, use alt="".
Styling media height
By default, slotted images render at their natural aspect ratio (height: auto). To constrain height, target the ::part(ag-card-media) shadow part or use a wrapping <div> with a fixed height and overflow: hidden inside the slot.
Clickable Card Pattern
Create fully clickable cards while maintaining accessibility:
<ag-card shadow animated>
<h4 slot="header" style="margin: 0;">
<a
href="/article"
class="card-primary-action"
style="text-decoration: none; color: inherit;"
>
Article Title
</a>
</h4>
<p>Article summary text...</p>
<button slot="footer" class="card-secondary-action">Bookmark</button>
</ag-card>The card-primary-action class creates a pseudo-element that covers the entire card, making it fully clickable. Elements with card-secondary-action class maintain their own click handlers.
Accessibility
- Cards are semantic containers that help organize content visually
- When using clickable cards, ensure the primary link is properly accessible
- Use appropriate heading levels within cards to maintain document outline
- Provide sufficient color contrast for variant cards
- Animation effects respect
prefers-reduced-motionuser preferences
Notes
- Combining Features: Multiple props can be combined (e.g.,
variant="success" :shadow="true" :animated="true") - Responsive Design: Cards are
width: 100%by default and work well in grid layouts - Lit Property Binding: In Lit templates, use property bindings for boolean props
- Reduced Motion: Animation transitions are automatically disabled for users who prefer reduced motion
- Media +
rounded: WhenhasMediaistrue,overflow: hiddenis applied to the host so the image clips correctly to the card's border-radius. No extra CSS is needed. - Media height: Slotted
<img>and<video>elements default towidth: 100%; height: auto; object-fit: cover. Constrain the height via::part(ag-card-media)or by wrapping the image in a sized<div>. - Horizontal layout: Inline-start/inline-end media positions are out of scope and deferred to a future issue.
- All three framework implementations share the same underlying styles and behavior