Astro components use the .astro file extension and have a unique syntax structure that combines server-side code and client-side templates.
Component Structure:
astro--- // 1. Frontmatter // Write server-side code here const title = "My Blog Post"; const date = new Date().toLocaleDateString(); // Can import other components import Card from './Card.astro'; // Can perform async operations const posts = await fetch('/api/posts').then(r => r.json()); --- <!-- 2. Template Area --> <!-- Write HTML/JSX here --> <h1>{title}</h1> <p>Published on {date}</p> <div class="posts"> {posts.map(post => ( <Card title={post.title} /> ))} </div> <style> /* 3. Scoped Styles */ h1 { color: #333; } </style>
Three Main Parts:
-
Frontmatter:
- Wrapped with
---delimiters - Executes at build time, not sent to browser
- Can use JavaScript/TypeScript
- Supports imports, async operations, data processing
- Wrapped with
-
Template Area:
- HTML-like syntax
- Supports expression interpolation
{variable} - Supports conditional rendering
{condition && <Component />} - Supports list rendering
{items.map(item => <Item />)}
-
Scoped Styles:
- Uses
<style>tag - Default is scoped styles
- Won't affect other components
- Can use
:global()selector for global styles
- Uses
Props Passing:
astro--- // Child component Card.astro const { title, description } = Astro.props; --- <div class="card"> <h2>{title}</h2> <p>{description}</p> </div> <style> .card { border: 1px solid #ddd; padding: 1rem; } </style>
Using child component:
astro--- import Card from './Card.astro'; --- <Card title="Article Title" description="Article Description" />
Slots:
astro--- // Layout.astro const { title } = Astro.props; --- <html> <head> <title>{title}</title> </head> <body> <header> <slot name="header" /> </header> <main> <slot /> <!-- Default slot --> </main> <footer> <slot name="footer" /> </footer> </body> </html>
Using layout:
astro--- import Layout from './Layout.astro'; --- <Layout title="My Page"> <slot slot="header"> <h1>Page Title</h1> </slot> <p>Main Content</p> <slot slot="footer"> <p>Footer Information</p> </slot> </Layout>
TypeScript Support:
astro--- interface Props { title: string; count?: number; } const { title, count = 0 } = Astro.props satisfies Props; --- <h1>{title}</h1> <p>Count: {count}</p>
Important Notes:
- Code in frontmatter doesn't execute in the browser
- Expressions in templates are evaluated at build time
- Styles are scoped by default and won't leak
- Components are static by default, use
client:*directives for interactivity - Can use components from any frontend framework in Astro components
Astro component syntax is simple yet powerful, providing excellent developer experience and performance.