Skip to content

Components Overview

Podcast Framework includes 8 production-ready Astro components that cover all common podcast website needs. All components are fully customizable through props and can be completely overridden by creating your own version.

  • Header - Main navigation header with logo, site name, and responsive mobile menu
  • Footer - Site footer with social links, copyright, and newsletter signup slot
  • SkeletonLoader - Loading placeholders in 4 variants (text, card, image, list)
ComponentPurposePropsOverride-able
HeaderNavigationsiteName, navigation, logoUrl
FooterSite footersiteName, social, showNewsletter
NewsletterSignupEmail capturetitle, description, endpoint
EpisodeSearchEpisode searchepisodes
TranscriptViewerShow transcriptstranscript, segments
FeaturedEpisodesCarouselEpisode carouselepisodes
SkeletonLoaderLoading statestype, count
BlockContentRich textblocks
---
import Header from '@rejected-media/podcast-framework-core/components/Header.astro';
import Footer from '@rejected-media/podcast-framework-core/components/Footer.astro';
---
<Header siteName="My Podcast" />
<Footer siteName="My Podcast" />
---
import { getEpisodes } from '@rejected-media/podcast-framework-core';
import EpisodeSearch from '@rejected-media/podcast-framework-core/components/EpisodeSearch.astro';
const episodes = await getEpisodes();
---
<EpisodeSearch episodes={episodes} />

Create your own version in src/components/:

my-podcast/
└── src/
└── components/
└── Header.astro ← Your custom header

The framework automatically uses your version instead of the default.

All components are mobile-first and fully responsive:

  • Mobile (< 768px) - Touch-friendly, stacked layouts
  • Tablet (768px - 1024px) - Balanced layouts
  • Desktop (> 1024px) - Full-featured layouts

Components respect the theme configured in Sanity CMS:

---
import Header from '@rejected-media/podcast-framework-core/components/Header.astro';
import { getPodcast } from '@rejected-media/podcast-framework-core';
const podcast = await getPodcast();
const theme = podcast?.theme;
---
<Header siteName={podcast?.name} theme={theme} />

Theme controls:

  • Colors (primary, secondary, background, text)
  • Fonts (heading, body)
  • Layout (border radius, spacing)

All components follow WCAG 2.1 AA standards:

  • Semantic HTML
  • ARIA labels
  • Keyboard navigation
  • Focus indicators
  • Screen reader support

All components have full TypeScript types:

export interface Props {
siteName: string;
logoUrl?: string;
navigation?: NavigationItem[];
theme?: Theme;
}

Use when you need a specific component:

---
import Header from '@rejected-media/podcast-framework-core/components/Header.astro';
---
<Header siteName="My Podcast" />

Use in layouts for automatic override detection:

---
import { getComponent } from '@rejected-media/podcast-framework-core';
const Header = getComponent('Header');
const Footer = getComponent('Footer');
---
<Header siteName="My Podcast" />
<Footer siteName="My Podcast" />

getComponent() checks src/components/ first, then falls back to framework.

Show components based on data:

---
import NewsletterSignup from '@rejected-media/podcast-framework-core/components/NewsletterSignup.astro';
import { getPodcast } from '@rejected-media/podcast-framework-core';
const podcast = await getPodcast();
const showNewsletter = podcast?.isActive;
---
{showNewsletter && (
<NewsletterSignup
title="Subscribe to our newsletter"
endpoint="/api/newsletter-subscribe"
/>
)}

Customize through props (easiest):

<Header
siteName="My Podcast"
logoUrl="/logo.png"
navigation={[
{ href: '/', label: 'Home' },
{ href: '/episodes', label: 'Episodes' },
{ href: '/custom', label: 'Custom Page' }
]}
/>

Override styles with custom CSS:

<Header siteName="My Podcast" />
<style>
header {
background: linear-gradient(to right, #667eea, #764ba2);
}
</style>

Create your own version:

src/components/Header.astro
---
export interface Props {
siteName: string;
}
const { siteName } = Astro.props;
---
<header>
<!-- Your completely custom header -->
<h1>{siteName}</h1>
</header>

Copy framework component and modify:

  1. Copy node_modules/@rejected-media/podcast-framework-core/components/Header.astro
  2. Paste to src/components/Header.astro
  3. Modify as needed

Components are optimized for performance:

  • Zero JavaScript (except interactive components)
  • Static by default - Pre-rendered at build time
  • Lazy loading - Images and heavy content load on demand
  • Small bundle size - Only ship what’s needed

Bundle Sizes:

  • Header: ~1 KB (with mobile menu script)
  • Footer: ~500 bytes
  • NewsletterSignup: ~2 KB (with validation)
  • EpisodeSearch: ~4 KB (with search logic)
  • TranscriptViewer: ~3 KB (with collapse logic)
  • FeaturedEpisodesCarousel: ~2 KB (with auto-progress)
  • SkeletonLoader: ~300 bytes
  • BlockContent: ~1 KB

Don’t rebuild what’s already there:

<!-- ❌ Don't do this -->
<header>
<nav>
<!-- Your custom navigation -->
</nav>
</header>
<!-- ✅ Do this -->
<Header siteName="My Podcast" navigation={myNav} />

Start with props, only override if truly necessary:

<!-- ✅ Good - Use props -->
<Header
siteName="My Podcast"
navigation={customNav}
/>
<!-- ⚠️ Only if props aren't enough -->
<!-- src/components/Header.astro -->

If overriding, keep it focused:

src/components/Header.astro
---
// Import and extend framework component
import FrameworkHeader from '@rejected-media/podcast-framework-core/components/Header.astro';
export interface Props {
siteName: string;
customProp?: string;
}
const { customProp, ...rest } = Astro.props;
---
<div class="header-wrapper">
{customProp && <div class="banner">{customProp}</div>}
<FrameworkHeader {...rest} />
</div>

Always test on multiple screen sizes:

Terminal window
# Dev server
npm run dev
# Test mobile: http://localhost:4321 (resize browser)
# Test tablet: 768px width
# Test desktop: 1024px+ width

If overriding, keep accessibility features:

<!-- Keep semantic HTML -->
<header>
<nav aria-label="Main navigation">
<!-- Navigation -->
</nav>
</header>
<!-- Keep ARIA labels -->
<button
aria-label="Toggle mobile menu"
aria-expanded="false"
>
Menu
</button>

Explore individual components:

Or learn about customization: