The CardContainer component is a reusable Astro component that wraps content in a styled card layout using the @fpkit/acss Card component. It provides consistent styling, shadows, borders, and optional titles for content sections across the application.
Overview
Section titled “Overview”Server-Rendered
Built as an Astro component for optimal SSR performance.
@fpkit/acss Integration
Uses Card component from @fpkit/acss for accessibility and semantic HTML.
Flexible Content
Accepts any content via slots - text, lists, components, or forms.
Optional Titles
Supports optional titles for content organization.
Features
Section titled “Features”- Consistent Styling: Pre-configured shadow, border, and rounded corners
- Flexible Layout: Uses Astro slots for maximum flexibility
- Semantic HTML: Renders as
<section>element with proper Card structure - Accessibility: Built on @fpkit/acss Card component with ARIA support
- Optional Titles: Display section titles when needed
- Dashboard Ready: Perfect for dashboard panels and content sections
Quick Start
Section titled “Quick Start”Installation
Section titled “Installation”The CardContainer component is located at:
src/components/astro/CardContainer.astroBasic Usage
Section titled “Basic Usage”---import CardContainer from '#components/astro/CardContainer.astro'---
<CardContainer> <p>Your content goes here</p></CardContainer>---import CardContainer from '#components/astro/CardContainer.astro'---
<CardContainer title="Section Title"> <p>Your content goes here</p></CardContainer>---import CardContainer from '#components/astro/CardContainer.astro'import EventList from '#components/react/EventList'---
<CardContainer title="Upcoming Events"> <p class="text-neutral-600 mb-4"> Showing upcoming events for this month </p> <EventList events={events} client:load /></CardContainer>Component API
Section titled “Component API”export type Props = { title?: string // Optional title displayed at top of card}| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
title | string | No | undefined | Optional title displayed in Card.Title section |
Styling
Section titled “Styling”The component comes pre-configured with:
- Shadow:
xlshadow for elevation - Border:
1px solidborder with--color-neutral-100 - Border Radius:
rounded-lgcorners - Width:
w-fullfor full container width - Border Style: Solid border with neutral color
Real-World Examples
Section titled “Real-World Examples”Dashboard Events Panel
Section titled “Dashboard Events Panel”Used in /dashboard/events to display event listings:
---import CardContainer from '#components/astro/CardContainer.astro'import { EventsListView } from '#components/react/EventsListView'import { getAllEvents, EVENT_LIST_FIELDS } from '#utils/events'
const events = await getAllEvents(50, true, undefined, EVENT_LIST_FIELDS)---
<section class="events-container w-full"> <CardContainer> <p class="text-neutral-600 mb-4 text-sm"> Showing {events.length} event{events.length !== 1 ? 's' : ''} </p> <EventsListView events={events} showActions={true} client:load /> </CardContainer></section>Upcoming Events
Section titled “Upcoming Events”Wrapping a list component in a titled container. /dashboard used this
composition until it moved to the Impact grid — the pattern still applies
anywhere a titled card wraps a list:
---import CardContainer from '#components/astro/CardContainer.astro'import UpcomingEvents from '#components/astro/UpcomingEvents.astro'---
<section> <CardContainer title="Upcoming Events"> <UpcomingEvents /> </CardContainer></section>Role-Protected Admin Panel
Section titled “Role-Protected Admin Panel”Combined with RoleGuard for role-based content:
---import CardContainer from '#components/astro/CardContainer.astro'import RoleGuard from '#components/astro/RoleGuard.astro'import { Link } from '@fpkit/acss'---
<section> <RoleGuard allowedRoles={['admin', 'super_admin']}> <CardContainer> <p>Access user management for advanced administration features.</p> <div style="text-align: center; margin-top: 2rem;"> <Link.LinkButton href="/dashboard/users">Go to User Management</Link.LinkButton> </div> </CardContainer> </RoleGuard></section>Use Cases
Section titled “Use Cases”Content Organization
Section titled “Content Organization”Use CardContainer to visually separate different content sections:
<section class="grid grid-cols-1 md:grid-cols-2 gap-4"> <CardContainer title="Recent Activity"> <!-- Activity feed content --> </CardContainer>
<CardContainer title="Quick Stats"> <!-- Statistics content --> </CardContainer></section>Form Containers
Section titled “Form Containers”Wrap forms in CardContainer for visual emphasis:
<CardContainer title="Create New Event"> <EventFormRHF csrfToken={csrfToken} client:load /></CardContainer>Dashboard Widgets
Section titled “Dashboard Widgets”Create consistent dashboard widget layouts:
<div class="dashboard-grid"> <CardContainer title="User Statistics"> <StatsDisplay stats={userStats} /> </CardContainer>
<CardContainer title="Recent Messages"> <MessageList messages={recentMessages} /> </CardContainer>
<CardContainer title="System Status"> <SystemHealthIndicator /> </CardContainer></div>Customization
Section titled “Customization”Custom Styling
Section titled “Custom Styling”While CardContainer comes with pre-configured styles, you can customize appearance:
<div class="custom-container"> <CardContainer title="Custom Styled Card"> <p>Content here</p> </CardContainer></div>
<style> .custom-container :global(section) { background: var(--color-primary-50); border-color: var(--color-primary-200); }</style><div class="p-6 bg-neutral-50"> <CardContainer title="Contained Card"> <p>Card with wrapper padding and background</p> </CardContainer></div><div class="grid grid-cols-1 md:grid-cols-3 gap-6"> <CardContainer title="Card 1"> <p>First card content</p> </CardContainer>
<CardContainer title="Card 2"> <p>Second card content</p> </CardContainer>
<CardContainer title="Card 3"> <p>Third card content</p> </CardContainer></div>Best Practices
Section titled “Best Practices”-
Use for Content Sections
CardContainer works best for distinct content sections that benefit from visual separation:
<!-- ✅ Good: Distinct content sections --><CardContainer title="User Profile"><UserProfileDisplay user={currentUser} /></CardContainer><CardContainer title="Recent Activity"><ActivityFeed activities={recentActivities} /></CardContainer> -
Combine with Path Aliases
Always import using path aliases for consistency:
---// ✅ Good: Path aliasimport CardContainer from '#components/astro/CardContainer.astro'// ❌ Bad: Relative path (do not do this)import CardContainer from '../../components/astro/CardContainer.astro'--- -
Title Consistency
Use titles consistently - either all sections have titles or none do:
<!-- ✅ Good: Consistent approach --><CardContainer title="Section 1">...</CardContainer><CardContainer title="Section 2">...</CardContainer><!-- ❌ Inconsistent: Mixed approach --><CardContainer title="Section 1">...</CardContainer><CardContainer>...</CardContainer> -
Responsive Layouts
Combine with responsive grid utilities for adaptive layouts:
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"><CardContainer title="Widget 1">...</CardContainer><CardContainer title="Widget 2">...</CardContainer><CardContainer title="Widget 3">...</CardContainer></div>
Component Source
Section titled “Component Source”The CardContainer component implementation:
---import { Card } from '@fpkit/acss'
export type Props = { title?: string}
const { title } = Astro.props---
<Card as="section" classes="shadow-md rounded-lg w-full border border-solid border-neutral-100" shadow="xl" style={{ border: 'solid 1px var(--color-neutral-100)' }}> { title && ( <Card.Title> <h3 class="text-lg font-semibold">{title}</h3> </Card.Title> ) } <Card.Content as="div"> <slot /> </Card.Content></Card>Key Features Explained
Section titled “Key Features Explained”as="section": Renders semantic<section>elementshadow="xl": Applies @fpkit/acss extra-large shadowclasses: Additional CSS classes for stylingstyle: Inline style for border customization<slot />: Accepts any child content
Related Components
Section titled “Related Components”- Card (from @fpkit/acss) - Base card component
- RoleGuard - Protect content based on user roles
- UpcomingEvents - Display upcoming events
- EventsListView - List view for events
Related Guides
Section titled “Related Guides”- Design System - Design tokens and utilities
- Role Guard Usage - Role-based content protection
- Events System - Working with events
Component Location: src/components/astro/CardContainer.astro
Used In:
/dashboard- Dashboard homepage/dashboard/events- Events listing page- Various protected dashboard sections