The astro-basics component library provides a collection of reusable, well-tested components for building modern web applications. All components are designed with accessibility, performance, and developer experience in mind.

Server-rendered components optimized for static content and SEO.

  • Location: src/components/astro/
  • Extension: .astro
  • Use Case: Layout, content display, server-side logic

Interactive components for client-side functionality.

  • Location: src/components/react/
  • Extension: .tsx
  • Use Case: Forms, interactive UI, state management

Specialized components for authenticated areas.

  • Location: src/components/dashboard/
  • Extension: .astro and .tsx
  • Use Case: Protected routes, user interfaces

Main site navigation and branding.

---
import { Header } from '#components/astro/Header.astro'
---
<Header title="My Site" showAuth={true} theme="light" />

Site footer. Renders the copyright line only, with the year taken from the current date. Takes no props.

---
import { Footer } from '#components/astro/Footer.astro'
---
<Footer />

Display blog posts and articles in card format.

---
import { PostCard } from '#components/astro/PostCard.astro'
---
<PostCard
title="Article Title"
description="Article description"
pubDate={new Date()}
author="Author Name"
href="/posts/article-slug"
featured={false}
/>

Navigation breadcrumbs for page hierarchy.

---
import { Breadcrumbs } from '#components/astro/Breadcrumbs.astro'
---
<Breadcrumbs
links={[{ text: 'Home', href: '/' }, { text: 'Blog', href: '/posts' }, { text: 'Current Page' }]}
/>

Client-side search functionality.

import { SearchBox } from '#components/react/SearchBox'
;<SearchBox placeholder="Search..." onSearch={query => console.log(query)} variant="default" />

Main layout wrapper for pages with support for custom headers.

Basic Usage:

---
import Base from '#layouts/Base.astro'
---
<Base pageTitle="Page Title" pageDescription="Page description" pageImageUrl="/og-image.jpg">
<!-- Page content -->
</Base>

Custom Header Slot:

The Base layout supports custom headers via named slots, allowing complete header customization:

---
import Base from '#layouts/Base.astro'
import CustomHeader from '#components/astro/CustomHeader.astro'
---
<Base>
<CustomHeader slot="header" />
<!-- Page content -->
</Base>

Header Options:

  1. Default Header - Automatic header with page metadata
  2. Custom Header - Use slot="header" for custom header component
  3. No Header - Set hideHeader={true} to hide header

Priority: Custom slot → Default Header → Hide (if hideHeader=true)

Props:

  • pageTitle - Page title for meta tags and header
  • pageDescription - Page description
  • pageImageUrl - Image shown in the page header
  • ogImage - Social share image path; defaults to /og/default.webp (generated by npm run og:images)
  • showBreadcrumb - Show/hide breadcrumb navigation
  • hideHeader - Hide the default header (ignored if custom header slot provided)

All components follow consistent prop patterns:

export type Props = {
title: string
description?: string // Prefer explicit over optional
className?: string
variant?: 'default' | 'primary' | 'secondary'
}

Components include full TypeScript support:

---
import type { Props } from './Component.astro'
const { title, description } = Astro.props as Props
---

Components use the project’s SCSS system:

// Component styles in src/styles/components/
@use '../tokens/colors' as *;
@use '../tokens/typography' as *;
.component {
color: var(--text-primary);
font-family: var(--font-family-base);
}

Design tokens are available as CSS variables:

.my-component {
--component-bg: var(--color-surface);
--component-text: var(--color-text-primary);
--component-border: var(--color-border);
}
---
import BaseLayout from '#layouts/BaseLayout.astro'
import Header from '#components/astro/Header.astro'
import Footer from '#components/astro/Footer.astro'
---
<BaseLayout title="My Page">
<Header title="Site Name" />
<main>
<!-- Page content -->
</main>
<Footer />
</BaseLayout>
---
import { getCollection } from 'astro:content'
import PostCard from '#components/astro/PostCard.astro'
const posts = await getCollection('posts')
const publishedPosts = posts.filter(post => post.data.publish)
---
<div class="posts-grid">
{
publishedPosts.map(post => (
<PostCard
title={post.data.title}
description={post.data.description}
pubDate={post.data.pubDate}
author={post.data.author}
href={`/posts/${post.slug}`}
featured={post.data.featured}
/>
))
}
</div>
// Use # alias for internal imports import Component from '#components/astro/Component.astro' // Use
import type for types import type {Props} from './types'
---
export type Props = {
title: string
description: string | undefined
}
const { title, description } = Astro.props
---
---
import InteractiveComponent from '#components/react/Interactive.tsx'
---
<!-- Only hydrate when needed -->
<InteractiveComponent client:load />
<InteractiveComponent client:visible />
<InteractiveComponent client:idle />
  1. Choose the right type: Astro for static, React for interactive
  2. Define clear props: Use TypeScript interfaces
  3. Follow naming conventions: PascalCase for component names
  4. Import directly: Use # path aliases (e.g. #components/astro/MyComponent.astro) — there is no barrel file
// Unit tests in /tests
import { describe, it, expect } from 'vitest'
describe('Component', () => {
it('should render correctly', () => {
// Test component behavior
})
})