Overview
The Astro Portfolio v3 project uses a well-organized component architecture that promotes reusability and maintainability. All components are built using Astro’s component syntax, which combines HTML, CSS, and JavaScript in a single file.
Components are located in ~/workspace/source/src/components/ and are organized by category: home/, navs/, shared/, and ui/.
Component Categories
Home Components
Navigation Components
Shared Components
UI Components
Home Section Components These components make up the various sections of the homepage and are located in src/components/home/. About Component Renders the about section with content from the content collection. ---
// src/components/home/About.astro
import SideNav from '../SideNav.astro' ;
import { getEntry } from 'astro:content' ;
const aboutContent = await getEntry ( 'about' , 'about-content' );
const { Content } = await aboutContent . render ();
---
< section class = 'py-20 relative' id = 'about' >
< div class = 'container-fluid relative' >
< h2 class = 'text-4xl font-semibold' > About me </ h2 >
< Content />
</ div >
</ section >
Location: src/components/home/About.astro:1Projects Component Displays featured projects from the projects content collection. Location: src/components/home/Projects.astro:1Work Experience Component Shows work history in a timeline format. Location: src/components/home/WorkExperience.astro:1Hero Components
HeroText.astro - Main hero text and CTA
HeroImage.astro - Hero section image/illustration
Blog Component Lists recent blog posts on the homepage. Location: src/components/home/Blogs.astro:1Navigation Components Navigation components provide site-wide navigation and are located in src/components/navs/. Navbar Component The main navigation bar with responsive design and active state handling. ---
// src/components/navs/Navbar.astro
import ThemeSwitcher from '@/components/shared/ThemeSwitcher.astro' ;
const navLinks = [
{ name: 'Home' , href: '/' },
{ name: 'About' , href: '#about' },
{ name: 'Work' , href: '#work' },
{ name: 'Projects' , href: '/projects' },
{ name: 'Advisory' , href: '/advisory' },
{ name: 'Contact' , href: '/contact' },
];
const isActive = ( href : string ) => {
// Active state logic
};
---
< header class = 'sticky top-0 z-50 py-6' >
< nav class = 'flex items-center justify-between' >
<!-- Navigation items -->
</ nav >
</ header >
Features:
Sticky positioning
Active link highlighting
Dropdown menu for “Writing” section
Integrated theme switcher
Profile image link to home
Location: src/components/navs/Navbar.astro:1Mobile Navigation Responsive mobile menu for smaller screens. Location: src/components/navs/MobileNav.astro:1Site footer with links and social media. Location: src/components/navs/Footer.astro:1Shared Components Reusable components used across multiple pages, located in src/components/shared/. Theme Switcher Allows users to cycle through available themes (light, dark, retro). See the Theming page for full details. Location: src/components/shared/ThemeSwitcher.astro:1Language Switcher Enables users to change the site language. ---
// src/components/shared/LanguageSwitcher.astro
import { languages , getLangFromUrl } from '@/utils/i18n' ;
const currentLang = getLangFromUrl ( Astro . url );
const currentPath = Astro . url . pathname . replace ( `/ ${ currentLang } ` , '' );
---
< div class = 'relative group' >
< button aria-label = 'Change language' >
<!-- Globe icon -->
</ button >
< div class = 'hidden group-hover:block' >
{ Object . entries ( languages ). map (([ lang , name ]) => (
< a href = { lang === 'en' ? `/ ${ currentPath } ` : `/ ${ lang } / ${ currentPath } ` } >
{ name }
</ a >
)) }
</ div >
</ div >
Location: src/components/shared/LanguageSwitcher.astro:1Article Card Displays a blog post preview card with image, title, description, and metadata. Location: src/components/shared/ArticleCard.astro:1Email subscription form for newsletter signups. Location: src/components/shared/NewsletterForm.astro:1Social Components
SocialLink.astro - Individual social media link
StickySocials.astro - Sticky social media sidebar
ShareModal.astro - Social sharing modal
Other Shared Components
BackgroundArt.astro - Decorative background elements
SectionHeader.astro - Consistent section headers
ResourceItem.astro - Resource list item
UI Components Base UI elements and icons located in src/components/ui/. Icon Components All icons are implemented as Astro components in src/components/ui/icons/: ArrowIcon.astro
CheckIcon.astro
---
// Simple arrow icon for CTAs
---
< svg class = "w-4 h-4" viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" >
< path stroke-linecap = "round" stroke-linejoin = "round" stroke-width = "2"
d = "M9 5l7 7-7 7" />
</ svg >
Available Icons:
ArrowIcon.astro - Navigation arrow
CheckIcon.astro - Checkmark
CopyIcon.astro - Copy to clipboard
GitHubIcon.astro - GitHub logo
LinkedInIcon.astro - LinkedIn logo
EmailIcon.astro - Email icon
DevToIcon.astro - Dev.to logo
Social sharing icons (Facebook, Twitter/X, WhatsApp, etc.)
Displays author information in article pages.
Location: src/components/AuthorSidebar.astro:1
Shows sponsor information and advertisements.
Location: src/components/SponsorsSidebar.astro:1
Side Navigation
Navigation sidebar for the about page.
Location: src/components/SideNav.astro:1
Component Patterns
Content Integration
Components frequently integrate with Astro’s Content Collections:
---
import { getEntry } from 'astro:content' ;
// Fetch content from a collection
const aboutContent = await getEntry ( 'about' , 'about-content' );
// Render markdown content
const { Content } = await aboutContent . render ();
---
< section >
< Content />
</ section >
Component Composition
Components are designed to be composable:
---
import { ThemeSwitcher , LanguageSwitcher } from '@/components/shared' ;
import { Navbar } from '@/components/navs' ;
---
< Navbar >
< div class = 'flex gap-2' >
< LanguageSwitcher />
< ThemeSwitcher />
</ div >
</ Navbar >
Client-Side Interactivity
Components with client-side behavior use inline <script> tags:
< button class = 'theme-toggle' >
Toggle Theme
</ button >
< script >
function initThemeToggle () {
const toggle = document . querySelector ( '.theme-toggle' );
toggle . addEventListener ( 'click' , () => {
// Handle theme switching
});
}
initThemeToggle ();
// Re-initialize after page transitions
document . addEventListener ( 'astro:after-swap' , initThemeToggle );
</ script >
The astro:after-swap event ensures components work correctly with Astro’s view transitions.
Styling Components
Components use Tailwind CSS utility classes for styling:
< button class = 'p-2 rounded-md hover:bg-accent transition-colors' >
Click me
</ button >
Theme-aware classes:
dark: prefix for dark mode styles
retro: prefix for retro theme styles
CSS variables for dynamic theming
Using Components
Import and Use
---
// Import from the components directory
import { About , Projects , WorkExperience } from '@/components/home' ;
import Navbar from '@/components/navs/Navbar.astro' ;
---
< Navbar />
< main >
< About />
< WorkExperience />
< Projects />
</ main >
Index Files
Component groups export their components via index.ts files:
// src/components/home/index.ts
export { default as About } from './About.astro' ;
export { default as Blogs } from './Blogs.astro' ;
export { default as HeroImage } from './HeroImage.astro' ;
export { default as HeroText } from './HeroText.astro' ;
export { default as Projects } from './Projects.astro' ;
export { default as WorkExperience } from './WorkExperience.astro' ;
This allows for clean imports:
import { About , Projects } from '@/components/home';
Creating New Components
To create a new component:
Choose the appropriate directory based on the component’s purpose
Create an .astro file with a descriptive name
Add to the index file if it’s part of a group
Follow naming conventions : PascalCase for component files
Example:
---
// src/components/shared/NewComponent.astro
interface Props {
title : string ;
description ?: string ;
}
const { title , description } = Astro . props ;
---
< div class = 'my-component' >
< h3 > { title } </ h3 >
{ description && < p > { description } </ p > }
</ div >
< style >
.my-component {
/* Component-scoped styles */
}
</ style >
Best Practices
Keep components focused - Each component should have a single responsibility
Use TypeScript interfaces - Define prop types for better type safety
Leverage content collections - Fetch content from collections rather than hardcoding
Make components responsive - Use Tailwind’s responsive prefixes
Handle page transitions - Use astro:after-swap for client-side scripts
Export from index files - Make component groups easier to import
Use semantic HTML - Ensure accessibility with proper HTML structure
Related Pages
Theming Learn how the ThemeSwitcher component works
i18n Understand the LanguageSwitcher implementation
Content Collections See how components integrate with content
Project Structure Understand the overall project organization