Claude-skill-registry astro-developer
Comprehensive Astro web framework development guidance for 2026. Use when building, configuring, or troubleshooting Astro projects; creating components; setting up routing; implementing islands architecture; working with React, Tailwind CSS, and Node.js integrations; testing; performance optimization; or deployment strategies. Includes TypeScript patterns, state management, API routes, and common pitfalls solutions.
git clone https://github.com/majiayu000/claude-skill-registry
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/astro-developer" ~/.claude/skills/majiayu000-claude-skill-registry-astro-developer && rm -rf "$T"
skills/data/astro-developer/SKILL.mdAstro Developer Skill
Overview
Enables comprehensive Astro web development including component creation, project setup, configuration optimization, islands architecture implementation, content collections management, and deployment strategies. This skill emphasizes Tailwind CSS-first development for consistent, maintainable styling.
Quick Start
Identify the task type and follow the corresponding workflow:
- New Project Setup → Use "Project Initialization" workflow
- Component Development → Use "Component Creation" guidelines with Tailwind CSS
- Testing Setup → See Testing Guide for Vitest/Playwright
- Performance Optimization → Use "Islands Architecture" patterns, see Performance Guide
- State Management → See State Management Guide for React islands
- Troubleshooting Issues → See Common Pitfalls Guide
- Content Management → Use "Content Collections" workflow
- Configuration & Deployment → Use "Configuration" and "Deployment" sections
Core Capabilities
1. Project Initialization & Setup
Create new Astro projects with optimal configurations:
# Basic Astro project npm create astro@latest my-project # With specific integrations npm create astro@latest -- --add react --add tailwind --add mdx # From template npm create astro@latest -- --template blog
Essential project structure to create:
src/ ├── components/ # Reusable Astro/UI framework components ├── layouts/ # Page layout templates ├── pages/ # File-based routing (REQUIRED) ├── styles/ # CSS/Sass files ├── content/ # Content collections (Markdown/MDX) └── env.d.ts # TypeScript environment types public/ # Static assets (robots.txt, favicon, etc) astro.config.mjs # Astro configuration tsconfig.json # TypeScript configuration package.json # Project dependencies and scripts
2. Component Creation
Astro Components (.astro)
Create server-rendered components with zero client-side JavaScript and Tailwind CSS styling:
--- // Component frontmatter - runs on server only import { SITE_TITLE } from '@/config'; export interface Props { title?: string; published?: Date; variant?: 'default' | 'primary' | 'secondary'; } const { title, published, variant = 'default' } = Astro.props; const variantClasses = { default: 'bg-white dark:bg-gray-800', primary: 'bg-blue-500 dark:bg-blue-600 text-white', secondary: 'bg-gray-100 dark:bg-gray-700' }; --- <!-- Component template - HTML with special syntax --> <html lang="en" class="h-full"> <head> <title>{title || SITE_TITLE}</title> </head> <body class="h-full m-0 font-sans leading-relaxed text-gray-900 dark:text-gray-100 bg-white dark:bg-gray-900"> <main class={`${variantClasses[variant]} p-6 rounded-lg shadow-sm`}> {title && <h1 class="text-2xl font-bold mb-4">{title}</h1>} {published && ( <time class="text-sm text-gray-600 dark:text-gray-400"> {published.toLocaleDateString()} </time> )} <slot /> <!-- Children content --> </main> </body> </html>
UI Framework Components (React, Vue, Svelte)
Add interactivity with client directives:
--- import ReactCounter from '@/components/ReactCounter.jsx'; import VueComponent from '@/components/VueComponent.vue'; import SvelteButton from '@/components/SvelteButton.svelte'; --- <!-- Load immediately --> <ReactCounter client:load /> <!-- Load when visible in viewport --> <SvelteButton client:visible /> <!-- Load when browser is idle --> <VueComponent client:idle /> <!-- Load only on mobile --> <ReactCounter client:load media="(max-width: 768px)" />
3. Islands Architecture
Implement optimal performance with selective hydration:
Client Islands Strategy
- Identify interactive components - Carousels, forms, modals
- Choose appropriate client directive:
- Immediately (headers, critical features)client:load
- When browser free (secondary features)client:idle
- When scrolled to (below-fold content)client:visible
- Based on media queryclient:media
--- import InteractiveHeader from '@/components/InteractiveHeader.astro'; import ImageCarousel from '@/components/ImageCarousel.jsx'; import NewsletterForm from '@/components/NewsletterForm.jsx'; import SocialShare from '@/components/SocialShare.jsx'; --- <!-- Above fold, critical interactivity --> <InteractiveHeader client:load /> <!-- Content heavy, load when visible --> <ImageCarousel client:visible /> <!-- Secondary feature, load when idle --> <NewsletterForm client:idle /> <!-- Mobile-only interactivity --> <SocialShare client:load media="(max-width: 768px)" />
Server Islands for Dynamic Content
Use
server:defer for personalized/dynamic content:
--- import UserProfile from '@/components/UserProfile.astro'; import RecommendedPosts from '@/components/RecommendedPosts.astro'; --- <!-- Static content loads immediately --> <main> <h1>Welcome to our blog</h1> <p>Explore our latest articles...</p> </main> <!-- Dynamic content loads in parallel --> <aside> <!-- User's profile with personalized data --> <UserProfile server:defer /> <!-- Recommended posts based on history --> <RecommendedPosts server:defer /> </aside>
4. Routing & Pages
File-Based Routing
Create pages using Astro's file-based routing:
src/pages/ ├── index.astro # → / ├── about.astro # → /about ├── blog/ │ ├── index.astro # → /blog │ ├── [slug].astro # → /blog/post-title │ └── [...page].astro # → /blog/2, /blog/3 └── api/ └── posts.json.js # → /api/posts (API endpoint)
Dynamic Routes
Handle dynamic segments with params:
--- // src/pages/blog/[slug].astro import { getCollection } from 'astro:content'; export async function getStaticPaths() { const posts = await getCollection('blog'); return posts.map((post) => ({ params: { slug: post.slug }, props: post, })); } const { Content, frontmatter } = Astro.props; --- <h1>{frontmatter.title}</h1> <p>Published: {frontmatter.pubDate.toLocaleDateString()}</p> <Content />
API Routes
Create server endpoints:
// src/pages/api/posts.json.js export async function GET() { return Response.json({ posts: [ { id: 1, title: "First post" }, { id: 2, title: "Second post" }, ], }); } export async function POST({ request }) { const data = await request.json(); // Process form submission return Response.json({ success: true }); }
5. Content Collections
Organize and validate content with type safety:
Configure Collections
// src/content/config.ts import { defineCollection, z } from "astro:content"; const blog = defineCollection({ schema: z.object({ title: z.string(), pubDate: z.date(), updatedDate: z.date().optional(), description: z.string(), heroImage: z.string().optional(), tags: z.array(z.string()).default([]), draft: z.boolean().default(false), }), }); const projects = defineCollection({ schema: z.object({ title: z.string(), description: z.string(), startDate: z.date(), endDate: z.date().optional(), technologies: z.array(z.string()), demoUrl: z.string().url().optional(), repoUrl: z.string().url().optional(), }), }); export const collections = { blog, projects };
Use Content in Pages
--- // src/pages/blog/index.astro import { getCollection } from 'astro:content'; import BlogLayout from '@/layouts/BlogLayout.astro'; import BlogPost from '@/components/BlogPost.astro'; const posts = await getCollection('blog', ({ data }) => !data.draft); const sortedPosts = posts.sort((a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf() ); --- <BlogLayout title="Blog"> {sortedPosts.map((post) => ( <BlogPost post={post} /> ))} </BlogLayout>
6. Styling & Integrations
Tailwind CSS Integration (Primary Styling Approach)
This skill emphasizes Tailwind CSS as the primary styling solution for all Astro projects.
// astro.config.mjs import tailwind from "@astrojs/tailwind"; export default defineConfig({ integrations: [tailwind()], });
Configure Tailwind for optimal performance:
// tailwind.config.js export default { content: ["./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}"], darkMode: "class", // Enables dark mode with .dark class theme: { extend: { fontFamily: { sans: ["Inter", "system-ui", "sans-serif"], }, colors: { // Define brand colors primary: { 50: "#eff6ff", 500: "#3b82f6", 600: "#2563eb", 900: "#1e3a8a", }, }, }, }, plugins: [], };
Global styles setup:
/* src/styles/global.css */ @tailwind base; @tailwind components; @tailwind utilities; @layer base { /* Custom base styles */ } @layer components { /* Custom component classes */ }
Tailwind CSS Best Practices
-
Use Custom Brand Colors: Always use the predefined brand colors from
global.css<!-- ✅ Use brand colors --> <div class="bg-mitra-blue text-warm-cream"> <div class="border-lush-green bg-warm-orange/10"> <!-- ❌ Avoid generic colors --> <div class="bg-blue-500 text-yellow-100"> <div class="border-green-500 bg-orange-100">Available brand colors:
- Primary:
,mitra-blue
,mitra-yellow
,lush-greenwarm-orange - Text:
,charcoal-greywarm-cream - Gradients:
(custom utility),bg-magic-gradient
with brand colorsbg-linear-to-br
- Primary:
-
Variant-based styling: Use JavaScript objects with brand colors
const buttonVariants = { primary: "bg-mitra-blue hover:bg-mitra-blue-dark text-white", secondary: "bg-warm-cream hover:bg-grey-100 text-charcoal-grey", accent: "bg-warm-orange hover:bg-warm-orange-dark text-white", }; -
Responsive design: Use Tailwind's responsive prefixes
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"> -
Dark mode: Implement with
prefixdark:<div class="bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100"> -
Composition: Combine utility classes with brand colors
<!-- ✅ Using brand colors --> <div class="flex flex-col items-center justify-center p-8 bg-linear-to-br from-mitra-blue/10 to-lush-green/10 rounded-2xl shadow-xl"> <div class="p-6 border border-warm-orange/20 bg-magic-gradient"> -
Custom properties: Use CSS variables for dynamic values
<div style="--delay: 100ms" class="animate-pulse [--delay:200ms]">
6. Tailwind CSS v4 Canonical Class Names
IMPORTANT: Tailwind CSS v4 uses different canonical class names. Always use these updated forms:
→bg-gradient-to-*
(e.g.,bg-linear-to-*
→bg-gradient-to-r
)bg-linear-to-r
→flex-shrink-0shrink-0
→aspect-[3/2]
(remove brackets for simple ratios)aspect-3/2
→grayscale-[30%]
(remove brackets for percentage values)grayscale-30
Examples:
<!-- Correct (Tailwind v4) --> <div class="bg-linear-to-r from-blue-500 to-purple-600 shrink-0 aspect-3/2 grayscale-30"> <!-- Incorrect (deprecated) --> <!-- These will trigger linter warnings: --> <!-- bg-gradient-to-r → should be bg-linear-to-r --> <!-- flex-shrink-0 → should be shrink-0 --> <!-- aspect-[3/2] → should be aspect-3/2 --> <!-- grayscale-[30%] → should be grayscale-30 -->
React Integration
// astro.config.mjs import react from "@astrojs/react"; export default defineConfig({ integrations: [react()], });
MDX Integration
// astro.config.mjs import mdx from "@astrojs/mdx"; export default defineConfig({ integrations: [mdx()], });
7. Performance Optimization
Image Optimization
--- import { Image } from 'astro:assets'; import heroImage from '@/images/hero.jpg'; --- <!-- Optimized, responsive images --> <Image src={heroImage} alt="Hero section background" widths={[400, 800, 1200]} formats={['avif', 'webp', 'jpg']} loading="eager" />
View Transitions
Enable smooth page transitions:
--- // src/layouts/MainLayout.astro import { ViewTransitions } from 'astro:transitions'; --- <html> <head> <ViewTransitions /> </head> <body> <header> <nav> <a href="/" transition:name="home">Home</a> <a href="/about" transition:name="about">About</a> </nav> </header> <main transition:name="main-content"> <slot /> </main> </body> </html>
8. Configuration Best Practices
Optimize astro.config.mjs
import { defineConfig } from "astro/config"; import react from "@astrojs/react"; import sitemap from "@astrojs/sitemap"; import tailwind from "@astrojs/tailwind"; export default defineConfig({ // Site metadata for SEO site: "https://yoursite.com", base: "/subpath", // If deploying to subdirectory // Integrations integrations: [react(), tailwind(), sitemap()], // Build optimizations build: { format: "directory", // Clean URLs assets: "_assets", // Custom assets path }, // Vite configurations vite: { optimizeDeps: { exclude: ["some-large-package"], }, }, // Server options for SSR output: "hybrid", // or 'server' or 'static' // Security headers security: { allowedHosts: ["yoursite.com"], }, });
TypeScript Configuration
// tsconfig.json { "extends": "astro/tsconfigs/strict", "compilerOptions": { "baseUrl": ".", "paths": { "@/*": ["./src/*"], "@/components/*": ["./src/components/*"], "@/layouts/*": ["./src/layouts/*"] }, "types": ["@astrojs/image/client"] }, "include": ["src/**/*.ts", "src/**/*.d.ts"] }
9. Deployment Strategies
Static Site Generation (Default)
npm run build # Creates static files in dist/
Deploy to:
- Vercel, Netlify, Cloudflare Pages
- GitHub Pages, GitLab Pages
- Any static hosting
Hybrid Rendering
// astro.config.mjs export default defineConfig({ output: 'hybrid', }); // Individual pages can opt-in to SSR --- export const prerender = false; ---
Server-Side Rendering
// astro.config.mjs export default defineConfig({ output: "server", adapter: node({ mode: "standalone", }), });
Deploy to:
- Node.js servers
- Docker containers
- Serverless platforms (Vercel, Netlify Functions)
10. Testing Strategies
See Testing Guide for comprehensive testing documentation.
Vitest for Unit Testing
npm install -D vitest @vitest/ui jsdom
// vitest.config.ts import { getViteConfig } from 'astro/config'; export default getViteConfig({ test: { environment: 'jsdom', include: ['src/**/*.{test,spec}.{js,ts,jsx,tsx}'], }, });
Playwright for E2E Testing
npm init playwright@latest
// playwright.config.ts import { defineConfig } from '@playwright/test'; export default defineConfig({ webServer: { command: 'npm run preview', url: 'http://localhost:4321/', }, });
Container API for Astro Components
import { experimental_AstroContainer as AstroContainer } from 'astro/container'; import { expect, test } from 'vitest'; import Card from '../src/components/Card.astro'; test('Card renders with props', async () => { const container = await AstroContainer.create(); const result = await container.renderToString(Card, { props: { title: 'Test' }, }); expect(result).toContain('Test'); });
11. TypeScript Best Practices
See Common Pitfalls Guide for TypeScript-specific issues.
Strict Mode Configuration
// tsconfig.json { "extends": "astro/tsconfigs/strict", "compilerOptions": { "strict": true, "noUnusedLocals": true, "noUnusedParameters": true, "noImplicitReturns": true, "baseUrl": ".", "paths": { "@/*": ["./src/*"], "@/components/*": ["./src/components/*"], "@/layouts/*": ["./src/layouts/*"] } } }
Type-Safe Props
--- export interface Props { title: string; count: number; isActive?: boolean; tags: string[]; } const { title, count, isActive = false, tags } = Astro.props; ---
12. State Management for React Islands
See State Management Guide for comprehensive patterns.
Zustand (Recommended)
// src/store/useStore.ts import { create } from 'zustand'; export const useStore = create((set) => ({ count: 0, increment: () => set((state) => ({ count: state.count + 1 })), }));
Usage Across Islands
// Component 1 import { useStore } from '@/store/useStore'; function Counter() { const { increment } = useStore(); return <button onClick={increment}>+</button>; } // Component 2 import { useStore } from '@/store/useStore'; function Display() { const count = useStore((state) => state.count); return <div>{count}</div>; }
Common Patterns & Solutions
Environment Variables
// Create .env file PUBLIC_API_URL=https://api.example.com SECRET_KEY=your-secret-key // Use in components const apiUrl = import.meta.env.PUBLIC_API_URL;
SEO Best Practices
--- // src/layouts/BaseLayout.astro interface Props { title: string; description: string; image?: string; url?: string; } const { title, description, image, url } = Astro.props; const siteUrl = Astro.site; const canonicalUrl = url ? new URL(url, siteUrl) : siteUrl; --- <html> <head> <title>{title}</title> <meta name="description" content={description} /> <link rel="canonical" href={canonicalUrl} /> {image && ( <meta property="og:image" content={new URL(image, siteUrl)} /> )} <meta property="og:title" content={title} /> <meta property="og:description" content={description} /> <meta property="og:url" content={canonicalUrl} /> <meta name="twitter:card" content="summary_large_image" /> </head> </html>
Error Handling
--- // src/pages/404.astro import Layout from '@/layouts/Layout.astro'; --- <Layout title="Not Found"> <h1>404 - Page not found</h1> <p>Sorry, we couldn't find that page.</p> </Layout>
// src/pages/error/[...code].astro export function getStaticPaths() { return [{ params: { code: "403" } }, { params: { code: "500" } }]; } const { code } = Astro.params; const errorMessages = { 403: "Forbidden", 500: "Internal Server Error", };
Common Issues & Solutions
Component Not Interactive
Problem: React/Vue components render but don't respond to user interaction.
Solution: Add
client:* directive. By default, Astro strips all client-side JavaScript.
--- import ReactComponent from '@/components/ReactComponent.jsx'; --- <!-- ❌ Wrong: No client directive --> <ReactComponent /> <!-- ✅ Correct: Add appropriate client directive --> <ReactComponent client:load />
Context API Not Working Across Islands
Problem: React Context providers don't share state between different component islands.
Solution: Each Astro island hydrates in isolation. Use external state management (Zustand, Redux, MobX) for cross-island state sharing.
See State Management Guide for detailed patterns.
document
or window
is Not Defined
documentwindowProblem: Error accessing browser APIs during server-side rendering.
Solution: Move browser-only code to
<script> tags or use lifecycle methods in framework components.
--- // ❌ Wrong: Browser API in frontmatter const width = window.innerWidth; --- <!-- ✅ Correct: Move to script tag --> <script> const width = window.innerWidth; </script>
TypeScript Ref Callback Errors
When using React refs with arrays in TypeScript, avoid this common error:
// ❌ Incorrect - TypeScript error <div ref={(el) => (cardsRef.current[index] = el)}> // ✅ Correct - Wrap the assignment <div ref={(el) => { cardsRef.current[index] = el; }}>
Tailwind CSS v4 Migration
Common issues when migrating from Tailwind CSS v3 to v4:
- Gradient classes: Always use
instead ofbg-linear-to-*bg-gradient-to-* - Aspect ratios: Use
instead ofaspect-3/2
for simple ratiosaspect-[3/2] - Flexbox: Use
instead ofshrink-0flex-shrink-0 - Filters: Use
instead ofgrayscale-30
for percentage valuesgrayscale-[30%]
File Path Resolution
If you encounter errors about missing files that should exist:
- Check if the file exists at the expected path
- The error might be from an outdated diagnostic cache
- Files may have been renamed or moved
Resources
scripts/
The scripts/ directory contains automation utilities:
- Generates component boilerplatecreate-component.js
- Batch image optimizationoptimize-images.js
- Custom sitemap generationgenerate-sitemap.js
Execute scripts without loading into context:
node scripts/create-component.js --name MyComponent --type astro
references/
Reference materials for detailed information:
- Common Astro component patternscomponent-patterns.md
- Detailed integration setup guides (React, Vue, Tailwind, MDX, etc.)integration-guide.md
- NEW: Comprehensive testing strategies with Vitest, Playwright, and Container APItesting-guide.md
- NEW: Common mistakes and solutions for islands architecture, client directives, SSR vs static renderingcommon-pitfalls.md
- NEW: Build optimization, image optimization, code splitting, deployment strategiesperformance-optimization.md
- NEW: State management patterns for React islands (Zustand, Redux Toolkit, Jotai, TanStack Query)state-management.md
Load reference materials when specific detailed information is needed:
Read references/testing-guide.md when setting up testing infrastructure Read references/common-pitfalls.md when troubleshooting hydration or directive issues Read references/performance-optimization.md when optimizing build size or load times Read references/state-management.md when implementing cross-island state sharing
assets/
Templates and boilerplate code:
- Starting templates for different component typescomponent-templates/
- Common layout patternslayout-templates/
- Page boilerplate for different use casespage-templates/
Use assets as starting points:
- Copy component templates for new components
- Reference layout templates for consistent structure
- Adapt page templates for common page types
This skill provides comprehensive Astro development guidance from project setup through deployment optimization.