• About Us
  • Privacy Policy
  • Disclaimer
  • Contact Us
AimactGrow
  • Home
  • Technology
  • AI
  • SEO
  • Coding
  • Gaming
  • Cybersecurity
  • Digital marketing
No Result
View All Result
  • Home
  • Technology
  • AI
  • SEO
  • Coding
  • Gaming
  • Cybersecurity
  • Digital marketing
No Result
View All Result
AimactGrow
No Result
View All Result

Crafting Sturdy DX With Astro Elements and TypeScript

Admin by Admin
April 27, 2025
Home Coding
Share on FacebookShare on Twitter


I’m an enormous fan of Astro’s give attention to developer expertise (DX) and the onboarding of recent builders. Whereas the essential DX is powerful, I can simply make a convoluted system that’s onerous to onboard my very own builders to. I don’t need that to occur.

If I’ve a number of builders engaged on a undertaking, I would like them to know precisely what to anticipate from each part that they’ve at their disposal. This goes double for myself sooner or later once I’ve forgotten the best way to work with my very own system!

To try this, a developer may go learn every part and get a robust grasp of it earlier than utilizing one, however that feels just like the onboarding could be extremely sluggish. A greater manner could be to arrange the interface in order that because the developer is utilizing the part, they’ve the best information instantly accessible. Past that, it could bake in some defaults that don’t enable builders to make expensive errors and alerts them to what these errors are earlier than pushing code!

Enter, in fact, TypeScript. Astro comes with TypeScript arrange out of the field. You don’t have to make use of it, however because it’s there, let’s discuss the best way to use it to craft a stronger DX for our growth groups.

Watch

I’ve additionally recorded a video model of this text which you could watch if that’s your jam. Test it out on YouTube for chapters and closed captioning.

Setup

On this demo, we’re going to make use of a primary Astro undertaking. To get this began, run the next command in your terminal and select the “Minimal” template.

npm create astro@newest

This may create a undertaking with an index route and a quite simple “Welcome” part. For readability, I like to recommend eradicating the  part from the path to have a clear start line to your undertaking.

So as to add a little bit of design, I’d suggest organising Tailwind for Astro (although, you’re welcome to model your part nevertheless you prefer to together with a mode block within the part).

npx astro add tailwind

As soon as that is full, you’re prepared to put in writing your first part.

Creating the essential Heading part

Let’s begin by defining precisely what choices we wish to present in our developer expertise.

For this part, we wish to let builders select from any HTML heading stage (H1-H6). We additionally need them to have the ability to select a particular font measurement and font weight — it might appear apparent now, however we don’t need individuals selecting a particular heading stage for the load and font measurement, so we separate these considerations.

Lastly, we wish to guarantee that any further HTML attributes will be handed by to our part. There are few issues worse than having a part after which not having the ability to do primary performance later.

Utilizing Dynamic tags to create the HTML component

Let’s begin by making a easy part that enables the consumer to dynamically select the HTML component they wish to use. Create a brand new part at ./src/elements/Heading.astro.

---
// ./src/part/Heading.astro
const { as } = Astro.props;
const As = as;
---


  

To make use of a prop as a dynamic component identify, we want the variable to begin with a capital letter. We are able to outline this as a part of our naming conference and make the developer at all times capitalize this prop of their use, however that feels inconsistent with how most naming works inside props. As a substitute, let’s preserve our give attention to the DX, and take that burden on for ourselves.

In an effort to dynamically register an HTML component in our part, the variable should begin with a capital letter. We are able to convert that within the frontmatter of our part. We then wrap all the kids of our part within the  part by utilizing Astro’s built-in  part.

Now, we are able to use this part in our index route and render any HTML component we wish. Import the part on the prime of the file, after which add  and 

 components to the route.

---
// ./src/pages/index.astro
import Format from '../layouts/Format.astro';
import Heading from '../elements/Heading.astro';

---


  Hiya!
  Hiya world
Showing the h1 and h3 elements inspected in DevTools.

This may render them appropriately on the web page and is a good begin.

Including extra customized props as a developer interface

Let’s clear up the component selecting by bringing it inline to our props destructuring, after which add in further props for weight, measurement, and any further HTML attributes.

To start out, let’s deliver the customized component selector into the destructuring of the Astro.props object. On the identical time, let’s set a wise default in order that if a developer forgets to move this prop, they nonetheless will get a heading.

---
// ./src/part/Heading.astro
const { as: As="h2" } = Astro.props;
---


  

Subsequent, we’ll get weight and measurement. Right here’s our subsequent design selection for our part system: can we make our builders know the category names they should use or do we offer a generic set of sizes and do the mapping ourselves? Since we’re constructing a system, I feel it’s essential to maneuver away from class names and right into a extra declarative setup. This may also future-proof our system by permitting us to vary out the underlying styling and sophistication system with out affecting the DX.

Not solely can we future proof it, however we are also capable of get round a limitation of Tailwind by doing this. Tailwind, because it seems can’t deal with dynamically-created class strings, so by mapping them, we resolve an instantaneous problem as properly.

On this case, our sizes will go from small (sm) to 6 instances the dimensions (6xl) and our weights will go from “mild” to “daring”.

Let’s begin by adjusting our frontmatter. We have to get these props off the Astro.props object and create a pair objects that we are able to use to map our interface to the right class construction.

---
// ./src/part/Heading.astro

const weights = {
    "daring": "font-bold",
    "semibold": "font-semibold",
    "medium": "font-medium",
    "mild": "font-light"
}
const sizes= {
    "6xl": "text-6xl",
    "5xl": "text-5xl",
    "4xl": "text-4xl",
    "3xl": "text-3xl",
    "2xl": "text-2xl",
    "xl": "text-xl",
    "lg": "text-lg",
    "md": "text-md",
    "sm": "text-sm"
}

const { as: As="h2", weight="medium", measurement="2xl" } = Astro.props;
---

Relying in your use case, this quantity of sizes and weights could be overkill. The beauty of crafting your individual part system is that you simply get to decide on and the one limitations are those you set for your self.

From right here, we are able to then set the lessons on our part. Whereas we may add them in a typical class attribute, I discover utilizing Astro’s built-in class:record directive to be the cleaner strategy to programmatically set lessons in a part like this. The directive takes an array of lessons that may be strings, arrays themselves, objects, or variables. On this case, we’ll choose the right measurement and weight from our map objects within the frontmatter.

---
// ./src/part/Heading.astro

const weights = {
  daring: "font-bold",
  semibold: "font-semibold",
  medium: "font-medium",
  mild: "font-light",
};
const sizes = {
  "6xl": "text-6xl",
  "5xl": "text-5xl",
  "4xl": "text-4xl",
  "3xl": "text-3xl",
  "2xl": "text-2xl",
  xl: "text-xl",
  lg: "text-lg",
  md: "text-md",
  sm: "text-sm",
};

const { as: As = "h2", weight = "medium", measurement = "2xl" } = Astro.props;
---


  

Your front-end should automatically shift a little in this update. Now your font weight will be slightly thicker and the classes should be applied in your developer tools.

Showing the h1 and h3 elements inspected in DevTools with the relevant classnames applied.

From here, add the props to your index route, and find the right configuration for your app.

---
// ./src/pages/index.astro
import Layout from '../layouts/Layout.astro';
import Heading from '../components/Heading.astro';
---


  Hello!
  Hello world
Showing the h1 and h3 elements inspected in DevTools revealing the applied classes.

Our custom props are finished, but currently, we can’t use any default HTML attributes, so let’s fix that.

Adding HTML attributes to the component

We don’t know what sorts of attributes our developers will want to add, so let’s make sure they can add any additional ones they need.

To do that, we can spread any other prop being passed to our component, and then add them to the rendered component.

---
// ./src/component/Heading.astro

const weights = {
  // etc.
};
const sizes = {
  // etc.
};

const { as: As = "h2", weight = "medium", size = "md", ...attrs } = Astro.props;
---


  

From here, we can add any arbitrary attributes to our element.

---
// ./src/pages/index.astro
import Layout from '../layouts/Layout.astro';
import Heading from '../components/Heading.astro';

---


  Hello!
  Hello world

I’d like to take a moment to truly appreciate one aspect of this code. Our , we add an id attribute. No big deal. Our 

, though, we’re adding an additional class. My original assumption when creating this was that this would conflict with the class:list set in our component. Astro takes that worry away. When the class is passed and added to the component, Astro knows to merge the class prop with the class:list directive and automatically makes it work. One less line of code!

Showing the h1 and h3 elements inspected in DevTools.

In many ways, I like to consider these additional attributes as “escape hatches” in our component library. Sure, we want our developers to use our tools exactly as intended, but sometimes, it’s important to add new attributes or push our design system’s boundaries. For this, we allow them to add their own attributes, and it can create a powerful mix.

It looks done, but are we?

At this point, if you’re following along, it might feel like we’re done, but we have two issues with our code right now: (1) our component has “red squiggles” in our code editor and (2) our developers can make a BIG mistake if they choose.

The red squiggles come from type errors in our component. Astro gives us TypeScript and linting by default, and sizes and weights can’t be of type: any. Not a big deal, but concerning depending on your deployment settings.

The other issue is that our developers don’t have to choose a heading element for their heading. I’m all for escape hatches, but only if they don’t break the accessibility and SEO of my site.

Imagine, if a developer used this with a div instead of an h1 on the page. What would happen?We don’t have to imagine, make the change and see.

Showing the div and h3 elements inspected in DevTools.

It looks identical, but now there’s no  element on the page. Our semantic structure is broken, and that’s bad news for many reasons. Let’s use typing to help our developers make the best decisions and know what options are available for each prop.

Adding types to the component

To set up our types, first we want to make sure we handle any HTML attributes that come through. Astro, again, has our backs and has the typing we need to make this work. We can import the right HTML attribute types from Astro’s typing package. Import the type and then we can extend that type for our own props. In our example, we’ll select the h1 types, since that should cover most anything we need for our headings.

Inside the Props interface, we’ll also add our first custom type. We’ll specify that the as prop must be one of a set of strings, instead of just a basic string type. In this case, we want it to be h1–h6 and nothing else.

---
// ./src/component/Heading.astro
import type { HTMLAttributes } from 'astro/types';

interface Props extends HTMLAttributes<'h1'>  "h6";


//... The rest of the file
---

After adding this, you’ll note that in your index route, the  component should now have a red underline for the as="div" property. When you hover over it, it will let you know that the as type does not allow for div and it will show you a list of acceptable strings.

If you delete the div, you should also now have the ability to see a list of what’s available as you try to add the string.

Showing a contextual menu that displays all of heading level options for the heading component while the code is being typed.

While it’s not a big deal for the element selection, knowing what’s available is a much bigger deal to the rest of the props, since those are much more custom.

Let’s extend the custom typing to show all the available options. We also denote these items as optional by using the ?:before defining the type.

While we could define each of these with the same type functionality as our as type, that doesn’t keep this future proofed. If we add a new size or weight, we’d have to make sure to update our type. To solve this, we can use a fun trick in TypeScript: keyof typeof.

There are two helper functions in TypeScript that will help us convert our weights and sizes object maps into string literal types:

  • typeof: This helper takes an object and converts it to a type. For instance typeof weights would return type { bold: string, semibold: string, ...etc}
  • keyof: This helper function takes a type and returns a list of string literals from that type’s keys. For instance keyof type { bold: string, semibold: string, ...etc} would return "bold" | "semibold" | ...etc which is exactly what we want for both weights and sizes.
---
// ./src/component/Heading.astro
import type { HTMLAttributes } from 'astro/types';

interface Props extends HTMLAttributes<'h1'>  "h3" 

// ... The rest of the file

Now, when we want to add a size or weight, we get a dropdown list in our code editor showing exactly what’s available on the type. If something is selected, outside the list, it will show an error in the code editor helping the developer know what they missed.

Showing a contextual menu that displays all of the size options for the heading component while the code is being typed.

While none of this is necessary in the creation of Astro components, the fact that it’s built in and there’s no additional tooling to set up means that using it is very easy to opt into.

I’m by no means a TypeScript expert, but getting this set up for each component takes only a few additional minutes and can save a lot of time for developers down the line (not to mention, it makes onboarding developers to your system much easier).

Tags: AstroComponentsCraftingStrongTypeScript
Admin

Admin

Next Post
Dune Awakening is getting a “giant scale” beta weekend, the final likelihood to style the spice earlier than the sport launches

Dune Awakening is getting a "giant scale" beta weekend, the final likelihood to style the spice earlier than the sport launches

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Recommended.

Attending RSAC 2025? This is Every part You Must Know

Attending RSAC 2025? This is Every part You Must Know

April 23, 2025
Co-founder of Elon Musk’s xAI departs the corporate

Co-founder of Elon Musk’s xAI departs the corporate

August 14, 2025

Trending.

Microsoft Launched VibeVoice-1.5B: An Open-Supply Textual content-to-Speech Mannequin that may Synthesize as much as 90 Minutes of Speech with 4 Distinct Audio system

Microsoft Launched VibeVoice-1.5B: An Open-Supply Textual content-to-Speech Mannequin that may Synthesize as much as 90 Minutes of Speech with 4 Distinct Audio system

August 25, 2025
New Assault Makes use of Home windows Shortcut Information to Set up REMCOS Backdoor

New Assault Makes use of Home windows Shortcut Information to Set up REMCOS Backdoor

August 3, 2025
Begin constructing with Gemini 2.0 Flash and Flash-Lite

Begin constructing with Gemini 2.0 Flash and Flash-Lite

April 14, 2025
The most effective methods to take notes for Blue Prince, from Blue Prince followers

The most effective methods to take notes for Blue Prince, from Blue Prince followers

April 20, 2025
Menace Actors Use Pretend DocuSign Notifications to Steal Company Information

Menace Actors Use Pretend DocuSign Notifications to Steal Company Information

May 28, 2025

AimactGrow

Welcome to AimactGrow, your ultimate source for all things technology! Our mission is to provide insightful, up-to-date content on the latest advancements in technology, coding, gaming, digital marketing, SEO, cybersecurity, and artificial intelligence (AI).

Categories

  • AI
  • Coding
  • Cybersecurity
  • Digital marketing
  • Gaming
  • SEO
  • Technology

Recent News

Tips on how to Monitor Key phrases: Ideas, Examples & Guidelines

Tips on how to Monitor Key phrases: Ideas, Examples & Guidelines

September 22, 2025
I Examined Herahaven AI Chat App for 1 Month

I Examined Herahaven AI Chat App for 1 Month

September 22, 2025
  • About Us
  • Privacy Policy
  • Disclaimer
  • Contact Us

© 2025 https://blog.aimactgrow.com/ - All Rights Reserved

No Result
View All Result
  • Home
  • Technology
  • AI
  • SEO
  • Coding
  • Gaming
  • Cybersecurity
  • Digital marketing

© 2025 https://blog.aimactgrow.com/ - All Rights Reserved