Importing Components
Composing components in Astro works exactly as you expect from React. Import in the frontmatter, use in the template. The import syntax is standard ES module syntax — the only requirement is that the import lives inside the --- frontmatter block.
Importing and using a component
Section titled “Importing and using a component”// src/pages/Home.jsximport Hero from '../components/Hero';import Footer from '../components/Footer';
export default function Home() { return ( <> <Hero title="Welcome" subtitle="Built with React" /> <main> <p>Page content here.</p> </main> <Footer /> </> );}---// src/pages/index.astroimport Hero from '../components/Hero.astro';import Footer from '../components/Footer.astro';---<Hero title="Welcome" subtitle="Built with Astro" /><main> <p>Page content here.</p></main><Footer />Key differences:
- Astro imports always go between the
---fences, not at the top of the file. .astrois a required extension in the import path (unlike React’s.jsx/.tsxwhich bundlers often resolve automatically).- An Astro page does not need a root wrapper element — the template is a document fragment.
Nesting and composition
Section titled “Nesting and composition”Composition works identically to React — pass props, pass slots, nest as deeply as you need. An Astro component can import and use other Astro components, React components (as islands), Svelte components, and more.
// PageLayout.jsximport Header from './Header';import Sidebar from './Sidebar';import Card from './Card';
export default function PageLayout({ posts }) { return ( <div className="layout"> <Header /> <div className="content"> <Sidebar /> <main> {posts.map((post) => ( <Card key={post.id} title={post.title} /> ))} </main> </div> </div> );}---// PageLayout.astroimport Header from './Header.astro';import Sidebar from './Sidebar.astro';import Card from './Card.astro';
const { posts } = Astro.props;---<div class="layout"> <Header /> <div class="content"> <Sidebar /> <main> {posts.map((post) => ( <Card title={post.title} /> ))} </main> </div></div>Note on the runnable snippet: The StackBlitz playground runs a single
src/pages/index.astrofile. The example below inlines the “sub-component” markup directly to stay self-contained. In a real project you would split it into separate.astrofiles and import them.
---
// Self-contained page — no separate component files needed
const team = [
{ name: "Alice", role: "Engineer" },
{ name: "Bob", role: "Designer" },
{ name: "Carol", role: "PM" },
];
---
<html lang="en">
<head><meta charset="utf-8" /><title>Team</title></head>
<body style="font-family:sans-serif;padding:2rem">
<header style="border-bottom:1px solid #e2e8f0;padding-bottom:1rem;margin-bottom:2rem">
<h1>Our Team</h1>
</header>
<ul style="list-style:none;padding:0;display:grid;gap:1rem">
{team.map((member) => (
<li style="border:1px solid #e2e8f0;border-radius:8px;padding:1rem">
<strong>{member.name}</strong>
<span style="color:#888;margin-left:.5rem">{member.role}</span>
</li>
))}
</ul>
</body>
</html>