Web components in MDX
Dropping interactive web components into blog posts — one home-made, one imported.
Most of this site ships zero JavaScript — Astro renders everything to static HTML. But when a post needs interactivity, web components are a perfect fit: they’re just HTML tags with behavior attached, no framework runtime required. Here are two in action.
A home-made component: <star-rating>
This one is defined in about seventy lines of vanilla TypeScript in
src/scripts/star-rating.ts — shadow DOM, keyboard-accessible buttons, and
a custom event when the rating changes. Click a star:
Using it in a post is one import and one tag:
import StarRating from '../../components/StarRating.astro';
<StarRating value={3} />
An imported component: <lite-youtube>
lite-youtube by Justin Ribeiro renders a YouTube embed as a static thumbnail and only loads the real iframe (and its ~1 MB of YouTube JavaScript) when you press play. Same one-tag usage:
import YouTube from '../../components/YouTube.astro';
<YouTube videoid="dQw4w9WgXcQ" videotitle="A very important video" />
Why wrap them in .astro components?
Both tags are wrapped in tiny Astro components (src/components/) whose
<script> block imports the element definition. Astro bundles and dedupes
those scripts automatically — use ten ratings on a page and the definition
still loads once. The pattern for adding any future web component is the
same three steps: install (or write) it, wrap it, import it in your post.