Create a Headings Component for an Astro Project with Svelte

  • astro
  • components
  • content delivery
  • headings
  • open source
  • responsive design
  • scalability
  • seo optimization
  • svelte
  • web performance
Dec 22, 2023
Enhance your Astro project by creating a dynamic Headings component with Svelte, optimized for SEO and performance.

Markdown Headings and SEO Optimization

Heading tags are the standard way to structure markdown content, playing a crucial role in SEO optimization by improving content delivery and ranking in search engines. Astro simplifies parsing markdown out of the box and seamlessly handles MDX content with its first-party MDX integration. This ensures that your content is both scalable and optimized for performance.

I enjoy using Svelte to create interactive and efficient components. Astro enhances this experience with its first-party Svelte integration, allowing for the development of highly responsive designs and mobile-first interfaces.

Here’s how I created a Headings component to parse all the headings from a markdown file or a list of headings and display them as clickable links, enhancing both user experience and SEO.

Headings Component for Enhanced Content Delivery

First, we will create a Headings.svelte component. This component is designed for flexibility, allowing it to be used in multiple contexts by accepting either an imported file or a list of headings directly.

Each .md or .mdx file can be imported using Astro’s built-in methods, which we’ll implement in the next section. Imported files contain various data points that are essential for key management and performance optimization, including:

  • url: The path to the file.
  • headings: A list of heading objects.

Each heading object in headings includes keys such as:

<!-- Headings.svelte -->

<script>
	// Props - accepts entire file or just the headings
	export let headings = [];
	export let file = {};

	// Check if the file has any keys
	const isFile = Object.keys(file).length > 0;

	// If the file has keys, use the headings from the file instead of the headings prop
	if (isFile) {
		headings = file.getHeadings();
	}
</script>

<!-- Iterate through each heading -->
{#each headings as heading}
	<div>
		<!-- 
			Prefix each heading with a # and indent accordingly
			with CSS classes based on heading.depth for responsive design
		-->
		<span
			class:ml-3={heading.depth === 3}
			class:ml-6={heading.depth === 4}
			class:ml-9={heading.depth === 5}
			class:ml-12={heading.depth === 6}
		>
			#
		</span>
		<!-- 
			Determine the link based on whether a file is passed in:
			- If a file is passed, link to the full path.
			- If only headings are passed, link to the specific ID on the page.
		-->
		<a href={isFile ? `${file.url}#${heading.slug}` : `#${heading.slug}`}>
			{heading.text}
		</a>
	</div>
{/each}

<style>
	div {
		display: flex;
		margin-bottom: 0.5rem;
	}
	span {
		margin-left: 0.25rem;
	}
	.ml-3 {
		margin-left: 0.75rem;
	}
	.ml-6 {
		margin-left: 1.5rem;
	}
	.ml-9 {
		margin-left: 2.25rem;
	}
	.ml-12 {
		margin-left: 3rem;
	}
</style>

Implementing the Headings Component

We can now integrate this component into our markdown layouts by providing headings, or by passing the entire file through the file prop in another page.

Markdown Layout for SEO-Friendly Headings

Create a layout for posts that displays the headings from your markdown file, enhancing content delivery and user navigation.

---
# @layouts/post/Post.astro

import Headings from "@components/Headings.svelte";

const { headings } = Astro.props;
---

<Headings headings={headings} />

<hr />

<slot />

Use this layout in your markdown file located in src/pages/posts/:

---
layout: "@layouts/post/Post.astro"
---

# Heading 1

## Heading 2

### Heading 3

Importing Headings in Other Pages for Enhanced SEO

To display headings as a preview outside of the page itself (e.g., on a homepage or a sidebar), you can import your files from src/pages/posts using Astro’s glob method. This approach leverages scalability and performance optimization.

---
# src/pages/index.astro

import Headings from "@components/Headings.svelte";

const posts = await Astro.glob("./posts/*");
---
<!-- Pass the first post into the component -->
<Headings file={posts[0]} />

Performance and SEO Benefits

Astro’s build-time rendering ensures that the Headings component is delivered to the client as optimized HTML and CSS with no additional JavaScript, enhancing web performance and scalability. This approach reduces energy consumption and aligns with sustainability and green practices by minimizing resource usage.

I’ve thoroughly enjoyed using Astro to create this blog. The first-party .mdx integration and Astro.glob method facilitate efficient content delivery and SEO optimization, making it an excellent choice for developers focused on responsive design and performance. I highly recommend Astro to others building static sites who prioritize SEO benefits and user experience.

Thanks for reading!