Components Medium
Showcase Preview Card
Live-preview card with an embedded iframe, difficulty badge, save-to-favorites, and Lab / View Code action buttons.
Open in Lab
MCP
css javascript
Targets: HTML
Code
:root {
color-scheme: dark;
font-family: "Inter", "Segoe UI", system-ui, -apple-system, sans-serif;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
min-height: 100vh;
background: #080808;
color: #e2e8f0;
}
.grid-stage {
min-height: 100vh;
padding: 2rem 1.5rem;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(min(300px, 100%), 1fr));
gap: 1.25rem;
align-content: start;
}
/* ─── Card ─── */
.showcase-card {
width: 100%;
border-radius: 16px;
background: rgba(255, 255, 255, 0.025);
border: 1px solid rgba(255, 255, 255, 0.08);
overflow: hidden;
transition: border-color 0.2s;
}
.showcase-card:hover {
border-color: rgba(255, 255, 255, 0.14);
}
/* ─── Preview iframe ─── */
.card-preview {
width: 100%;
aspect-ratio: 4 / 3;
overflow: hidden;
border-bottom: 1px solid rgba(255, 255, 255, 0.07);
}
.preview-frame {
width: 100%;
height: 100%;
border: none;
pointer-events: none;
}
/* ─── Body ─── */
.card-body {
padding: 1.125rem 1.125rem 1rem;
display: flex;
flex-direction: column;
gap: 0.625rem;
}
.card-meta-row {
display: flex;
align-items: center;
gap: 0.5rem;
}
.card-category {
font-size: 0.7rem;
color: rgba(255, 255, 255, 0.32);
text-transform: uppercase;
letter-spacing: 0.06em;
flex: 1;
}
.difficulty {
font-size: 0.65rem;
font-weight: 600;
padding: 2px 8px;
border-radius: 999px;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.difficulty.easy { background: rgba(74, 222, 128, 0.12); color: #4ade80; }
.difficulty.med { background: rgba(251, 191, 36, 0.12); color: #fbbf24; }
.difficulty.hard { background: rgba(248, 113, 113, 0.12); color: #f87171; }
.fav-btn {
background: none;
border: none;
cursor: pointer;
color: rgba(255, 255, 255, 0.28);
padding: 3px;
border-radius: 5px;
line-height: 0;
transition: color 0.15s;
}
.fav-btn:hover { color: #f87171; }
.fav-btn.active { color: #f87171; }
.fav-btn.active .heart { fill: #f87171; }
.card-title {
font-size: 0.9375rem;
font-weight: 600;
color: #f8fafc;
line-height: 1.3;
}
.card-desc {
font-size: 0.8rem;
color: rgba(255, 255, 255, 0.4);
line-height: 1.6;
}
/* ─── Actions ─── */
.card-actions {
display: flex;
gap: 8px;
margin-top: 0.25rem;
}
.btn-lab,
.btn-code {
display: inline-flex;
align-items: center;
gap: 5px;
padding: 6px 14px;
border-radius: 8px;
font-size: 0.75rem;
font-weight: 500;
text-decoration: none;
transition: background 0.15s, color 0.15s;
}
.btn-lab {
color: rgba(255, 255, 255, 0.6);
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.08);
}
.btn-lab:hover {
background: rgba(255, 255, 255, 0.1);
color: #f8fafc;
}
.btn-code {
color: #f8fafc;
background: rgba(79, 70, 229, 0.2);
border: 1px solid rgba(79, 70, 229, 0.3);
}
.btn-code:hover {
background: rgba(79, 70, 229, 0.32);
}<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Showcase Preview Card</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<main class="grid-stage">
<article class="showcase-card" data-slug="glow-metric-card">
<!-- Live iframe preview -->
<div class="card-preview">
<iframe
class="preview-frame"
title="Glow Metric Card preview"
sandbox="allow-scripts"
srcdoc="
<!doctype html>
<html>
<head>
<style>
*{box-sizing:border-box;margin:0;padding:0}
body{min-height:100vh;display:grid;place-items:center;background:radial-gradient(circle at top,#0f172a 0%,#020617 60%);font-family:system-ui,sans-serif}
.card{position:relative;width:240px;padding:22px 20px;border-radius:18px;background:rgba(15,23,42,0.8);border:1px solid rgba(148,163,184,0.2);overflow:hidden;box-shadow:0 20px 40px rgba(15,23,42,0.4)}
.card::before{content:'';position:absolute;inset:-30% 10% 40% -10%;background:radial-gradient(circle,rgba(56,189,248,0.35),transparent 60%);filter:blur(20px);z-index:0}
.label{position:relative;z-index:1;font-size:0.75rem;letter-spacing:0.08em;text-transform:uppercase;color:#94a3b8;margin-bottom:10px}
.value{position:relative;z-index:1;font-size:2rem;font-weight:700;color:#f8fafc;line-height:1;margin-bottom:12px}
.meta{position:relative;z-index:1;display:flex;align-items:center;gap:8px;font-size:0.8rem;color:#94a3b8}
.delta{padding:3px 9px;border-radius:999px;background:rgba(34,197,94,0.15);color:#4ade80;font-weight:600}
</style>
</head>
<body>
<div class='card'>
<p class='label'>Active users</p>
<p class='value'>24,680</p>
<div class='meta'><span class='delta'>+12%</span><span>vs last month</span></div>
</div>
</body>
</html>
"
></iframe>
</div>
<!-- Card info -->
<div class="card-body">
<div class="card-meta-row">
<span class="card-category">Components</span>
<span class="difficulty easy">Easy</span>
<button class="fav-btn" aria-label="Save to favorites" aria-pressed="false">
<svg class="heart" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/>
</svg>
</button>
</div>
<h2 class="card-title">Glow Metric Card</h2>
<p class="card-desc">A compact metric card with a soft gradient glow and hover lift for dashboards.</p>
<div class="card-actions">
<a href="#" class="btn-lab">
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/>
<polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/>
</svg>
Lab
</a>
<a href="#" class="btn-code">View Code</a>
</div>
</div>
</article>
<article class="showcase-card" data-slug="skeleton-loader">
<div class="card-preview">
<iframe
class="preview-frame"
title="Skeleton Loader preview"
sandbox="allow-scripts"
srcdoc="<!doctype html><html><head><style>*{box-sizing:border-box;margin:0;padding:0}body{min-height:100vh;display:grid;place-items:center;background:#0a0a0a;font-family:system-ui,sans-serif;padding:2rem}.card{width:280px;padding:1.25rem;border-radius:14px;background:rgba(255,255,255,0.03);border:1px solid rgba(255,255,255,0.08);display:flex;flex-direction:column;gap:.75rem}@keyframes shimmer{0%{background-position:-400px 0}100%{background-position:400px 0}}.sk{border-radius:6px;background:linear-gradient(90deg,rgba(255,255,255,0.05) 25%,rgba(255,255,255,0.1) 50%,rgba(255,255,255,0.05) 75%);background-size:800px 100%;animation:shimmer 1.4s infinite linear}.sk-title{height:14px;width:70%}.sk-text{height:10px}.sk-text-short{height:10px;width:55%}.sk-tags{display:flex;gap:6px}.sk-tag{height:20px;width:48px;border-radius:999px}.sk-footer{display:flex;justify-content:space-between;align-items:center}.sk-badges{display:flex;gap:4px}.sk-badge{height:18px;width:36px;border-radius:4px}.sk-btn{height:28px;width:52px;border-radius:7px}</style></head><body><div class='card'><div class='sk sk-title'></div><div class='sk sk-text'></div><div class='sk sk-text-short'></div><div class='sk-tags'><div class='sk sk-tag'></div><div class='sk sk-tag'></div><div class='sk sk-tag'></div></div><div class='sk-footer'><div class='sk-badges'><div class='sk sk-badge'></div><div class='sk sk-badge'></div></div><div class='sk sk-btn'></div></div></div></body></html>"
></iframe>
</div>
<div class="card-body">
<div class="card-meta-row">
<span class="card-category">Patterns</span>
<span class="difficulty easy">Easy</span>
<button class="fav-btn" aria-label="Save to favorites" aria-pressed="false">
<svg class="heart" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/>
</svg>
</button>
</div>
<h2 class="card-title">Skeleton Loader</h2>
<p class="card-desc">Animated shimmer placeholders that match your layout while content loads.</p>
<div class="card-actions">
<a href="#" class="btn-lab">Lab</a>
<a href="#" class="btn-code">View Code</a>
</div>
</div>
</article>
<article class="showcase-card" data-slug="aurora-text">
<div class="card-preview">
<iframe
class="preview-frame"
title="Aurora Text preview"
sandbox="allow-scripts"
srcdoc="<!doctype html><html><head><style>*{box-sizing:border-box;margin:0;padding:0}body{min-height:100vh;display:grid;place-items:center;background:#030712;font-family:system-ui,sans-serif}@keyframes aurora{0%,100%{background-position:0% 50%}50%{background-position:100% 50%}}.text{font-size:clamp(2rem,8vw,3.5rem);font-weight:800;letter-spacing:-0.04em;background:linear-gradient(135deg,#38bdf8,#818cf8,#e879f9,#38bdf8);background-size:300% 300%;-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;animation:aurora 4s ease infinite}</style></head><body><p class='text'>Aurora Text</p></body></html>"
></iframe>
</div>
<div class="card-body">
<div class="card-meta-row">
<span class="card-category">Web Animations</span>
<span class="difficulty easy">Easy</span>
<button class="fav-btn" aria-label="Save to favorites" aria-pressed="false">
<svg class="heart" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/>
</svg>
</button>
</div>
<h2 class="card-title">Aurora Text</h2>
<p class="card-desc">Animated gradient text cycling through aurora colors using CSS background-position.</p>
<div class="card-actions">
<a href="#" class="btn-lab">Lab</a>
<a href="#" class="btn-code">View Code</a>
</div>
</div>
</article>
</main>
<script>
document.querySelectorAll('.fav-btn').forEach(btn => {
const slug = btn.closest('[data-slug]').dataset.slug;
const favs = JSON.parse(localStorage.getItem('st_favorites') || '[]');
if (favs.includes(slug)) { btn.setAttribute('aria-pressed', 'true'); btn.classList.add('active'); }
btn.addEventListener('click', () => {
const f = JSON.parse(localStorage.getItem('st_favorites') || '[]');
const i = f.indexOf(slug);
if (i === -1) { f.push(slug); btn.setAttribute('aria-pressed','true'); btn.classList.add('active'); }
else { f.splice(i,1); btn.setAttribute('aria-pressed','false'); btn.classList.remove('active'); }
localStorage.setItem('st_favorites', JSON.stringify(f));
});
});
</script>
</body>
</html>Showcase Preview Card
A masonry-friendly card that renders a live preview inside a sandboxed <iframe> using srcdoc. Below the preview sits a metadata row with category label, title, description, difficulty badge, and action buttons for Lab and View Code links.
Features
srcdociframe for inline live previews- Difficulty badge (Easy / Med / Hard)
- Favorite toggle backed by localStorage
- Lab and View Code CTA buttons
- Masonry-compatible: no fixed height
When to use
- Showcase or gallery pages with live component previews
- Component library browse pages
- Any grid that needs interactive card previews