1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
|
---
layout: ~/layouts/Main.astro
title: Astro Components
---
**Astro Components** (files ending with `.astro`) are the foundation of server-side templating in Astro. Think of the Astro component syntax as HTML enhanced with JavaScript.
Learning a new syntax can feel intimidating, so we carefully designed the Astro component syntax to feel as familiar to web developers as possible. It borrows heavily from patterns you likely already know: components, frontmatter, props, and JSX expressions. We're confident that this guide will have you writing Astro components in no time, especially if you are already familiar with HTML & JavaScript.
## Syntax Overview
A single `.astro` file represents a single Astro component in your project. This pattern is known as a **Single-File Component (SFC)**. Both Svelte (`.svelte`) and Vue (`.vue`) also follow this pattern.
Below is a walk-through of the different pieces and features of the Astro component syntax. You can read it start-to-finish, or jump between sections.
### HTML Template
Astro component syntax is a superset of HTML. **If you know HTML, you already know enough to write your first Astro component.**
For example, this three-line file is a valid Astro component:
```html
<!-- Example1.astro - Static HTML is a valid Astro component! -->
<div class="example-1">
<h1>Hello world!</h1>
</div>
```
An Astro component represents some snippet of HTML in your project. This can be a reusable component, or an entire page of HTML including `<html>`, `<head>` and `<body>` elements. See our guide on [Astro Pages](/guides/astro-pages) to learn how to build your first full HTML page with Astro.
**Every Astro component must include an HTML template.** While you can enhance your component in several ways (see below) at the end of the day its the HTML template that dictates what your rendered Astro component will look like.
### CSS Styles
CSS rules inside of a `<style>` tag are automatically scoped to that component. That means that you can reuse class names across multiple components, without worrying about conflicts. Styles are automatically extracted and optimized in the final build so that you don't need to worry about style loading.
For best results, you should only have one `<style>` tag per-Astro component. This isn’t necessarily a limitation, but it will often result in better-optimized CSS in your final build. When you're working with pages, the `<style>` tag can go nested inside of your page `<head>`. For standalone components, the `<style>` tag can go at the top-level of your template.
```html
<!-- Astro Component CSS example -->
<style>
.circle {
background-color: red;
border-radius: 999px;
height: 50px;
width: 50px;
}
<div class="circle"></div>
```
```html
<!-- Astro Page CSS example -->
<html>
<head>
<style>
...;
</style>
</head>
<body>
...
</body>
</html>
```
Sass (an alternative to CSS) is also available via `<style lang="scss">`.
📚 Read our full guide on [Component Styling](/guides/styling) to learn more.
### Frontmatter Script
To build a dynamic components, we introduce the idea of a frontmatter component script. [Frontmatter](https://jekyllrb.com/docs/front-matter/) is a common pattern in Markdown, where some config/metadata is contained inside a code fence (`---`) at the top of the file. Astro does something similar, but with full support for JavaScript & TypeScript in your components.
Remember that Astro is a server-side templating language, so your component script will run during the build but only the HTML is rendered to the browser. To send JavaScript to the browser, you can use a `<script>` tag in your HTML template or [convert your component to use a frontend framework](/core-concepts/component-hydration) like React, Svelte, Vue, etc.
```astro
---
// Anything inside the `---` code fence is your component script.
// This JavaScript code runs at build-time.
// See below to learn more about what you can do.
console.log('This runs at build-time, is visible in the CLI output');
// Tip: TypeScript is also supported out-of-the-box!
const thisWorks: number = 42;
---
<div class="example-1">
<h1>Hello world!</h1>
</div>
```
### Component Imports
An Astro component can reuse other Astro components inside of its HTML template. This becomes the foundation of our component system: build new components and then reuse them across your project.
To use an Astro component in your template, you first need to import it in the frontmatter component script. An Astro component is always the file's default import.
Once imported, you can use it like any other HTML element in your template. Note that an Astro component **MUST** begin with an uppercase letter. Astro will use this to distinguish between native HTML elements (`form`, `input`, etc.) and your custom Astro components.
```astro
---
// Import your components in your component script...
import SomeComponent from './SomeComponent.astro';
---
<!-- ... then use them in your HTML! -->
<div>
<SomeComponent />
</div>
```
📚 You can also import and use components from other frontend frameworks like React, Svelte, and Vue. Read our guide on [Component Hydration](/core-concepts/component-hydration) to learn more.
### Dynamic JSX Expressions
Instead of inventing our own custom syntax for dynamic templating, we give you direct access to JavaScript values inside of your HTML, using something that feels just like [JSX](https://reactjs.org/docs/introducing-jsx.html).
Astro components can define local variables inside of the Frontmatter script. Any script variables are then automatically available in the HTML template below.
#### Dynamic Values
```astro
---
const name = "Your name here";
---
<div>
<h1>Hello {name}!</h1>
</div>
```
#### Dynamic Attributes
```astro
---
const name = "Your name here";
---
<div>
<div data-name={name}>Attribute expressions supported</div>
<div data-hint={`Use JS template strings to mix ${"variables"}.`}>So good!</div>
</div>
```
#### Dynamic HTML
```astro
---
const items = ["Dog", "Cat", "Platipus"];
---
<ul>
{items.map((item) => (
<li>{item}</li>
))}
</ul>
```
### Component Props
An Astro component can define and accept props. Props are available on the `Astro.props` global in your frontmatter script.
```astro
---
// Example: <SomeComponent greeting="(Optional) Hello" name="Required Name" />
const { greeting = 'Hello', name } = Astro.props;
---
<div>
<h1>{greeting}, {name}!</h1>
</div>
```
You can define your props with TypeScript by exporting a `Props` type interface. In the future, Astro will automatically pick up any exported `Props` interface and give type warnings/errors for your project.
```astro
---
// Example: <SomeComponent /> (WARNING: "name" prop is required)
export interface Props {
name: string;
greeting?: string;
}
const { greeting = 'Hello', name } = Astro.props;
---
<div>
<h1>{greeting}, {name}!</h1>
</div>
```
### Slots
`.astro` files use the [`<slot>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/slot) tag to enable component composition. Coming from React or Preact, this is the same concept as `children`. You can think of the `<slot>` element as a placeholder for markup which will be passed in from outside of the component.
```astro
<!-- Example: MyComponent.astro -->
<div id="my-component">
<slot /> <!-- children will go here -->
</div>
<!-- Usage -->
<MyComponent>
<h1>Hello world!</h1>
</MyComponent>
```
Slots become even more powerful when using **named slots**. Rather than a single `<slot>` element which renders _all_ children, named slots allow you to specify multiple places where children should be placed.
> **Note** The `slot` attribute is not restricted to plain HTML, components can use `slot` as well!
```astro
<!-- Example: MyComponent.astro -->
<div id="my-component">
<header>
<!-- children with the `slot="header"` attribute will go here -->
<slot name="header" />
</header>
<main>
<!-- children without a `slot` (or with the `slot="default"`) attribute will go here -->
<slot />
</main>
<footer>
<!-- children with the `slot="footer"` attribute will go here -->
<slot name="footer">
</footer>
</div>
<!-- Usage -->
<MyComponent>
<h1 slot="header">Hello world!</h1>
<p>Lorem ipsum ...</p>
<FooterComponent slot="footer" />
</MyComponent>
```
Slots can also render **fallback content**. When there are no matching children passed to a `<slot>`, a `<slot>` element will render its own placeholder children.
```astro
<!-- MyComponent.astro -->
<div id="my-component">
<slot>
<h1>I will render when this slot does not have any children!</h1>
</slot>
</div>
<!-- Usage -->
<MyComponent />
```
### Fragments & Multiple Elements
An Astro component template can render as many top-level elements as you'd like. Unlike other UI component frameworks, you don't need to wrap everything in a single `<div>` if you'd prefer not to.
```html
<!-- An Astro component can multiple top-level HTML elements: -->
<div id="a" />
<div id="b" />
<div id="c" />
```
When working inside a JSX expression, however, you must wrap multiple elements inside of a **Fragment**. Fragments let you render a set of elements without adding extra nodes to the DOM. This is required in JSX expressions because of a limitation of JavaScript: You can never `return` more than one thing in a JavaScript function or expression. Using a Fragment solves this problem.
A Fragment must open with `<>` and close with `</>`. Don't worry if you forget this, Astro's compiler will warn you that you need to add one.
```astro
---
const items = ["Dog", "Cat", "Platipus"];
---
<ul>
{items.map((item) => (
<>
<li>Red {item}</li>
<li>Blue {item}</li>
<li>Green {item}</li>
</>
))}
</ul>
```
### Slots
Sometimes, an Astro component will be passed children. This is especially common for components like sidebars or dialog boxes that represent generic "wrappers” around content.
```astro
<WrapChildrenWithText>
<img src="https://placehold.co/400" />
<WrapChildrenWithText>
```
Astro provides a `<slot />` component so that you can control where any children are rendered within the component. This is heavily inspired by the [`<slot>` HTML element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/slot).
```astro
---
// Example: components/WrapChildrenWithText.astro
// Usage: <WrapChildrenWithText><img src="https://placehold.co/400" /><WrapChildrenWithText>
// Renders: <h1>Begin</h1><img src="https://placehold.co/400" /><h1>End</h1>
---
<h1>Begin</h1>
<!-- slot: any given children are injected here -->
<slot />
<h1>End</h1>
```
<!-- TODO: https://github.com/snowpackjs/astro/issues/600
If you don't provide a `<slot />` component in your HTML template, any children passed to your component will not be rendered. -->
<!-- TODO: https://github.com/snowpackjs/astro/issues/360
Document Named Slots -->
## Comparing `.astro` versus `.jsx`
`.astro` files can end up looking very similar to `.jsx` files, but there are a few key differences. Here's a comparison between the two formats.
| Feature | Astro | JSX |
| ---------------------------- | ------------------------------------------ | -------------------------------------------------- |
| File extension | `.astro` | `.jsx` or `.tsx` |
| User-Defined Components | `<Capitalized>` | `<Capitalized>` |
| Expression Syntax | `{}` | `{}` |
| Spread Attributes | `{...props}` | `{...props}` |
| Children | `<slot>` (with named slot support) | `children` |
| Boolean Attributes | `autocomplete` === `autocomplete={true}` | `autocomplete` === `autocomplete={true}` |
| Inline Functions | `{items.map(item => <li>{item}</li>)}` | `{items.map(item => <li>{item}</li>)}` |
| IDE Support | WIP - [VS Code][code-ext] | Phenomenal |
| Requires JS import | No | Yes, `jsxPragma` (`React` or `h`) must be in scope |
| Fragments | Automatic top-level, `<>` inside functions | Wrap with `<Fragment>` or `<>` |
| Multiple frameworks per-file | Yes | No |
| Modifying `<head>` | Just use `<head>` | Per-framework (`<Head>`, `<svelte:head>`, etc) |
| Comment Style | `<!-- HTML -->` | `{/* JavaScript */}` |
| Special Characters | ` ` | `{'\xa0'}` or `{String.fromCharCode(160)}` |
| Attributes | `dash-case` | `camelCase` |
## URL resolution
It’s important to note that Astro **won’t** transform HTML references for you. For example, consider an `<img>` tag with a relative `src` attribute inside `src/pages/about.astro`:
```html
<!-- ❌ Incorrect: will try and load `/about/thumbnail.png` -->
<img src="./thumbnail.png" />
```
Since `src/pages/about.astro` will build to `/about/index.html`, you may not have expected that image to live at `/about/thumbnail.png`. So to fix this, choose either of two options:
### Option 1: Absolute URLs
```html
<!-- ✅ Correct: references public/thumbnail.png -->
<img src="/thumbnail.png" />
```
The recommended approach is to place files within `public/*`. This references a file it `public/thumbnail.png`, which will resolve to `/thumbnail.png` at the final build (since `public/` ends up at `/`).
### Option 2: Asset import references
```astro
---
// ✅ Correct: references src/thumbnail.png
import thumbnailSrc from './thumbnail.png';
---
<img src={thumbnailSrc} />
```
If you’d prefer to organize assets alongside Astro components, you may import the file in JavaScript inside the component script. This works as intended but this makes `thumbnail.png` harder to reference in other parts of your app, as its final URL isn’t easily-predictable (unlike assets in `public/*`, where the final URL is guaranteed to never change).
[code-ext]: https://marketplace.visualstudio.com/items?itemName=astro-build.astro-vscode
|