Components Easy
Resource Card
Grid card for code resources with tech badges, difficulty label, target framework pills, and a save-to-favorites toggle.
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: 1rem;
align-content: start;
}
.resource-card {
width: 100%;
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: 0.75rem;
transition: border-color 0.2s, background 0.2s, transform 0.2s;
cursor: default;
}
.resource-card:hover {
border-color: rgba(255, 255, 255, 0.14);
background: rgba(255, 255, 255, 0.05);
transform: translateY(-2px);
}
.card-header {
display: flex;
align-items: center;
justify-content: space-between;
}
.card-meta {
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;
}
.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; }
.favorite-btn {
background: none;
border: none;
cursor: pointer;
color: rgba(255, 255, 255, 0.28);
padding: 4px;
border-radius: 6px;
display: flex;
transition: color 0.15s, background 0.15s;
line-height: 0;
}
.favorite-btn:hover {
color: #f87171;
background: rgba(248, 113, 113, 0.1);
}
.favorite-btn.active {
color: #f87171;
}
.favorite-btn.active .heart-icon {
fill: #f87171;
}
.card-title {
font-size: 0.9375rem;
font-weight: 600;
color: #f8fafc;
line-height: 1.3;
}
.card-description {
font-size: 0.8125rem;
color: rgba(255, 255, 255, 0.42);
line-height: 1.65;
}
.card-tags {
display: flex;
flex-wrap: wrap;
gap: 0.375rem;
}
.tag {
font-size: 0.7rem;
padding: 3px 8px;
border-radius: 6px;
background: rgba(255, 255, 255, 0.05);
color: rgba(255, 255, 255, 0.38);
border: 1px solid rgba(255, 255, 255, 0.06);
}
.card-footer {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 0.125rem;
}
.target-badges {
display: flex;
gap: 0.375rem;
}
.target {
font-size: 0.65rem;
font-weight: 500;
padding: 2px 7px;
border-radius: 5px;
background: rgba(99, 102, 241, 0.1);
color: #818cf8;
border: 1px solid rgba(99, 102, 241, 0.15);
}
.btn-lab {
display: flex;
align-items: center;
gap: 5px;
padding: 5px 12px;
border-radius: 7px;
font-size: 0.75rem;
font-weight: 500;
color: rgba(255, 255, 255, 0.55);
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.08);
text-decoration: none;
transition: background 0.15s, color 0.15s;
}
.btn-lab:hover {
background: rgba(255, 255, 255, 0.1);
color: #f8fafc;
}<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Resource Card</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<main class="grid-stage">
<article class="resource-card" data-slug="animated-tab-bar">
<header class="card-header">
<div class="card-meta">
<span class="card-category">UI Components</span>
<span class="difficulty easy">Easy</span>
</div>
<button class="favorite-btn" aria-label="Save to favorites" aria-pressed="false">
<svg class="heart-icon" width="16" height="16" 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>
</header>
<h2 class="card-title">Animated Tab Bar</h2>
<p class="card-description">A smooth animated tab bar with sliding underline indicator and spring transition for navigation.</p>
<div class="card-tags">
<span class="tag">css</span>
<span class="tag">javascript</span>
<span class="tag">animation</span>
<span class="tag">tabs</span>
</div>
<footer class="card-footer">
<div class="target-badges"><span class="target">HTML</span><span class="target">React</span></div>
<a href="#" class="btn-lab">Lab</a>
</footer>
</article>
<article class="resource-card" data-slug="skeleton-loader">
<header class="card-header">
<div class="card-meta">
<span class="card-category">Patterns</span>
<span class="difficulty easy">Easy</span>
</div>
<button class="favorite-btn" aria-label="Save to favorites" aria-pressed="false">
<svg class="heart-icon" width="16" height="16" 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>
</header>
<h2 class="card-title">Skeleton Loader</h2>
<p class="card-description">Animated shimmer placeholders that match your layout while content loads asynchronously.</p>
<div class="card-tags">
<span class="tag">css</span>
<span class="tag">animation</span>
<span class="tag">loading</span>
<span class="tag">ux</span>
</div>
<footer class="card-footer">
<div class="target-badges"><span class="target">HTML</span><span class="target">React</span></div>
<a href="#" class="btn-lab">Lab</a>
</footer>
</article>
<article class="resource-card" data-slug="parallax-scroll">
<header class="card-header">
<div class="card-meta">
<span class="card-category">Web Animations</span>
<span class="difficulty med">Med</span>
</div>
<button class="favorite-btn" aria-label="Save to favorites" aria-pressed="false">
<svg class="heart-icon" width="16" height="16" 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>
</header>
<h2 class="card-title">Parallax Scroll Hero</h2>
<p class="card-description">Multi-layer scroll-driven parallax background with depth separation using CSS custom properties.</p>
<div class="card-tags">
<span class="tag">css</span>
<span class="tag">scroll</span>
<span class="tag">parallax</span>
<span class="tag">hero</span>
</div>
<footer class="card-footer">
<div class="target-badges"><span class="target">HTML</span></div>
<a href="#" class="btn-lab">Lab</a>
</footer>
</article>
<article class="resource-card" data-slug="command-palette">
<header class="card-header">
<div class="card-meta">
<span class="card-category">UI Components</span>
<span class="difficulty hard">Hard</span>
</div>
<button class="favorite-btn" aria-label="Save to favorites" aria-pressed="false">
<svg class="heart-icon" width="16" height="16" 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>
</header>
<h2 class="card-title">Command Palette</h2>
<p class="card-description">⌘K command menu with fuzzy search, keyboard navigation, and grouped results.</p>
<div class="card-tags">
<span class="tag">css</span>
<span class="tag">javascript</span>
<span class="tag">keyboard</span>
<span class="tag">search</span>
<span class="tag">accessibility</span>
</div>
<footer class="card-footer">
<div class="target-badges"><span class="target">HTML</span><span class="target">React</span></div>
<a href="#" class="btn-lab">Lab</a>
</footer>
</article>
<article class="resource-card" data-slug="toast-notification">
<header class="card-header">
<div class="card-meta">
<span class="card-category">UI Components</span>
<span class="difficulty easy">Easy</span>
</div>
<button class="favorite-btn" aria-label="Save to favorites" aria-pressed="false">
<svg class="heart-icon" width="16" height="16" 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>
</header>
<h2 class="card-title">Toast Notification</h2>
<p class="card-description">Stacked toast notifications with slide-in animation, variants, and auto-dismiss timer.</p>
<div class="card-tags">
<span class="tag">css</span>
<span class="tag">javascript</span>
<span class="tag">notification</span>
<span class="tag">animation</span>
</div>
<footer class="card-footer">
<div class="target-badges"><span class="target">HTML</span><span class="target">React</span></div>
<a href="#" class="btn-lab">Lab</a>
</footer>
</article>
<article class="resource-card" data-slug="glassmorphism-card">
<header class="card-header">
<div class="card-meta">
<span class="card-category">Design Styles</span>
<span class="difficulty easy">Easy</span>
</div>
<button class="favorite-btn" aria-label="Save to favorites" aria-pressed="false">
<svg class="heart-icon" width="16" height="16" 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>
</header>
<h2 class="card-title">Glassmorphism Card</h2>
<p class="card-description">Frosted-glass card using backdrop-filter blur with a layered gradient border glow.</p>
<div class="card-tags">
<span class="tag">css</span>
<span class="tag">glassmorphism</span>
<span class="tag">backdrop-filter</span>
</div>
<footer class="card-footer">
<div class="target-badges"><span class="target">HTML</span></div>
<a href="#" class="btn-lab">Lab</a>
</footer>
</article>
</main>
<script>
document.querySelectorAll('.favorite-btn').forEach(btn => {
const slug = btn.closest('[data-slug]').dataset.slug;
const saved = JSON.parse(localStorage.getItem('st_favorites') || '[]');
if (saved.includes(slug)) {
btn.setAttribute('aria-pressed', 'true');
btn.classList.add('active');
}
btn.addEventListener('click', () => {
const favs = JSON.parse(localStorage.getItem('st_favorites') || '[]');
const idx = favs.indexOf(slug);
if (idx === -1) {
favs.push(slug);
btn.setAttribute('aria-pressed', 'true');
btn.classList.add('active');
} else {
favs.splice(idx, 1);
btn.setAttribute('aria-pressed', 'false');
btn.classList.remove('active');
}
localStorage.setItem('st_favorites', JSON.stringify(favs));
});
});
</script>
</body>
</html>Resource Card
A dark-themed grid card for browsing code snippets and component demos. Shows title, description, tech tags, difficulty badge, target framework pills, and a favorite heart button backed by localStorage.
Features
- Color-coded difficulty badge (Easy / Med / Hard)
- Up to 5 tech tag pills with overflow counter
- Favorite toggle persisted in localStorage
- Target framework badges (HTML, React, Vue, etc.)
- Hover lift and border highlight
When to use
- Component or snippet library browsing pages
- Template or boilerplate galleries
- Any searchable, filterable resource grid