DEV Community

Cover image for Build your interface in Astro: Components 🧩
Domenico Tenace for This is Learning

Posted on • Updated on • Originally published at javascript.plainenglish.io

Build your interface in Astro: Components 🧩

Overview

Every frontend framework is based on the concept of Components: Vue, Angular, React use this powerful feature to build complete applications.
Astro is no exception, and in this article we will see what Components is and how to use it in an Astro project.
Let's start! 🤙


What are Astro Components?

Astro Components are reusable pieces of code and they are HTML-only templating components with no client-side runtime.
The extension of these files is .astro.
Astro components are extremely flexible because you can use them in different ways:

  • It can contain some reusable UI on the page like footer or navbar.
  • It may contain a collection of common <meta> tags that make SEO easy to work with.
  • It can even contain an entire page layout.

It is important to know that Astro Components do not render on the client, it's possible include JavaScript code inside of your component frontmatter, and all of it will be stripped from the final page sent to your use's browsers.

The Structure

An Astro Component is made up of two main parts: script and the template.



---
// Component Script (JavaScript or Typescript code)
---
<!-- Component Template (HTML + JS Expressions) -->


Enter fullscreen mode Exit fullscreen mode

You can use the script to write any JavaScript code that you need to render your template, for example:

  • importing other Astro components
  • importing other framework components, like Vue
  • importing data, like a JSON file
  • fetching content from an API or database



import SomeAstroComponent from '../components/SomeAstroComponent.astro';
import SomeReactComponent from '../components/SomeVueComponent.vue';
import someData from '../data/data.json';

const { title } = Astro.props;

const data = await fetch('example/posts').then(r => r.json());


Enter fullscreen mode Exit fullscreen mode

This approach is highly secure because at build time, the JavaScript code will not end up in the end user's browser.

Instead the template determines the HTML output of your component: if you write plain HTML here, your component will render that HTML in any Astro page it is imported and used.
Astro’s component template syntax also supports JavaScript expressions, <style> and <script> tags, imported components, and special Astro directives.
Data and values defined in the component script can be used in the component template to produce dynamically-created HTML, like Vue or React.



---
// Your component script here!
import Banner from '../components/Banner.astro';
import VueCardComponent from '../components/VueCardComponent.vue';
const myFavoriteFruits = [/* ... */];
const { title } = Astro.props;
---

<Banner />
<h1>Hello, Astro!</h1>

 <p>{title}</p>

<VueCardComponent client:visible />

<ul>
  {myFavoriteFruits.map((data) => <li>{data.name}</li>)}
</ul>

<p class:list={["add", "dynamic", {classNames: true}]} />


Enter fullscreen mode Exit fullscreen mode

Props

An Astro component can define and accept props. These props then become available to the component template for rendering HTML. Props are available on the Astro.props global in your script.

Declaration:



---
 const { greeting, name } = Astro.props;
---
<h2>{greeting}, {name}!</h2>


Enter fullscreen mode Exit fullscreen mode

Usage:



<GreetingHeadline greeting="Hello" name="World" />


Enter fullscreen mode Exit fullscreen mode

It's possible define your props with TypeScript with a Props type interface. Astro will automatically pick up the Props interface in your frontmatter and give type warnings/errors.



---
interface Props {
  name: string;
  greeting?: string;
}

const { greeting = "Hello", name } = Astro.props;
---
<h2>{greeting}, {name}!</h2>


Enter fullscreen mode Exit fullscreen mode

Slots

The <slot /> element is a placeholder for external HTML content, allowing you to inject child elements from other files into your component template.

By default, all child elements passed to a component will be rendered in its <slot />.
For example:



---
import Header from './Header.astro';
import Logo from './Logo.astro';
import Footer from './Footer.astro';

const { title } = Astro.props;
---
<div id="content-wrapper">
  <Header />
  <Logo />
  <h1>{title}</h1>
  <slot />  
  <Footer />
</div>



Enter fullscreen mode Exit fullscreen mode


---
import Wrapper from '../components/Wrapper.astro';
---
<Wrapper title="John's Page">
  <h2>All about John</h2>
  <p>Here is some stuff about John.</p>
</Wrapper>


Enter fullscreen mode Exit fullscreen mode

Named Slots

An Astro component can also have named slots. This allows you to pass only HTML elements with the corresponding slot name so you can place different elements in as many places.



---
import Header from './Header.astro';
import Logo from './Logo.astro';
import Footer from './Footer.astro';

const { title } = Astro.props;
---
<div id="content-wrapper">
  <Header />
  <slot name="after-header" />  
  <Logo />
  <h1>{title}</h1>
  <slot /> 
  <Footer />
  <slot name="after-footer" />
</div>


Enter fullscreen mode Exit fullscreen mode

To inject HTML content into a particular slot, use the slot attribute on any child element to specify the name of the slot, in this way:



---
import Wrapper from '../components/Wrapper.astro';
---
<Wrapper title="Fred's Page">
  <img src="https://myphoto/john.jpg" slot="after-header" />
  <h2>All about John</h2>
  <p>Here is some stuff about John.</p>
  <p slot="after-footer">Copyright 2024</p>
</Wrapper>


Enter fullscreen mode Exit fullscreen mode

HTML Components, it's possible

Astro supports importing and using .html files as components. You may want to use HTML components if you’re reusing code from an existing site built without a framework, or if you want to ensure that your component has no dynamic features.

HTML components must contain only valid HTML, and therefore lack key Astro component features:

  • They don’t support frontmatter, server-side imports, or dynamic expressions.
  • Any <script> tags are left unbundled, treated as if they had is:inline.
  • They can only reference assets that are in the public/ folder.

Conclusion

Astro Components are fundamental for build your UI. Their encapsulation of functionality, reusability, and ease of integration make them a powerful tool for building scalable and maintainable website.
Happy coding!✨


Hi👋🏻
My name is Domenico, software developer passionate of Vue.js framework, I write article about it for share my knowledge and experience.
Don't forget to visit my Linktree to discover my projects 🫰🏻

Linktree: https://linktr.ee/domenicotenace

Follow me on dev.to for other articles 👇🏻

If you like my content or want to support my work on GitHub, you can support me with a very small donation.
I would be grateful 🥹

Buy Me A Coffee

Top comments (5)

Collapse
 
ferdnyc profile image
Frank Dana • Edited

See, this is where I feel like things get a bit messy. So, the final page will be rendered with the Wrapper.astro template formatting all of the content from... let's call it Fred.astro, with the contents of the Wrapper tag placed at the location of Wrapper's <slot /> tag... EXCEPT for the paragraph with the named slot attribute, which will be placed in the position of Wrapper's other, named slot tag.

So, ultimately, the final content may be completely rearranged from how it's written. And what if the named-slot paragraph is inside a styled <div> in the Fred document, but the named slot tag is inside a differently-styled <div> In the Wrapper template?

I assume the styles from Wrapper prevail, and the Fred div is simply ignored.
But the ambiguity inherent in slots rearranging the document hierarchy make me a bit uneasy.

Collapse
 
dvalin99 profile image
Domenico Tenace

The style of the wrapper component also overrides the content, and this can be negative and positive at the same time: nice to reuse a template for the whole project, but I also had situations where I needed a specific style.

It's something that can make you uncomfortable, it's true.

Collapse
 
doublefaces profile image
DoubleFacess

English version of the commenti, for everyone: Hello here, I'm a vue developer, more Nuxtjs than vue, but I'm testing astro and I'm impressed by its speed, relative simplicity and power. I've tried integrating vue components and they work great. What do you think about Astro as a framework compared to Nuxt and Nextjs? Are we forgetting any notable frameworks above?

Collapse
 
dvalin99 profile image
Domenico Tenace

Hi, I'll answer you in English so they can understand all :)
I think it all depends on the project. If you are developing a Web App, I would not use Astro, but solutions like Vue, or if you need SSR and SEO attention, Nuxt (or Next).

Astro is useful in circumstances where you have content-oriented projects (a blog for example).

I hope I have helped you and if you have any other doubts and questions you can safely write to me privately :)

Collapse
 
doublefaces profile image
DoubleFacess

Hello here, sono uno sviluppatore vue, più Nuxtjs che vue, ma sto testando astro e sono rimasto favorevolmente colpito dalla sua velocità, relativa semplicità e potenza. Ho provato ad integrare componenti vue e funzionano egregiamente. Che ne pensi di Astro come framework rispetto a Nuxt e Nextjs? Dimentichiamo qualche framework di rilievo tra quelli qui sopra?