Proper websites, done properly

Part 9: Navigation improvements and social metadata

5 minute read time / 573 words

Our navigation is very basic at the moment, and that's fine because it's a simple site - but there's still things we can do to improve it. Let's get our social sharing in good shape too.

The first thing we can do to improve our navigation is to add a class to set different styles for it when it's the current page we're on. We can do this by comparing the URL of the page we're outputting with the current page we're on using Astro.url. In our Nav component, update the map function to check this:

{navPages.map(page =>
    <a
        href={page.url}
        class={(Astro.url.pathname === page.url) && 'is_active'}
    >
        {page.title}
    </a>
)}

We can also improve the accessibility of the current link by correctly setting the aria-current attribute to 'page' when we set the link's class to active too.

{navPages.map(page =>
    <a
        href={page.url}
        class={(Astro.url.pathname === page.url) && 'is_active'}
        aria-current={(Astro.url.pathname === page.url) ? 'page' : 'false'}
    >
        {page.title}
    </a>
)}

Social sharing metadata

Open up our layout template and let's add the missing stuff. Firstly, we need to create a couple of new page variables in the frontmatter and then populate all the required Open Graph and X (previously Twitter) Twitter cards meta elements.

---
import Header from '../components/Header.astro';
import Footer from '../components/Footer.astro';
import Nav from '../components/Nav.astro';

const { title, description } = Astro.props;
const xhandle = "MySexyAstro";
const author = "My Sexy Astro Site";
---
<!DOCTYPE html>
<html lang="en-GB">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width">
        <title>{title} | My Sexy Astro Site</title>

        <meta property="og:site_name" content="My Sexy Astro Site">
        <meta property="og:title" content={title}>
        <meta property="og:description" content={description}>
        <meta property="og:type" content="website">
        <meta property="og:image" content={`${Astro.site}img/social/sharer.jpg`}>
        <meta property="og:image:width" content="1280">
        <meta property="og:image:height" content="800">
        <meta property="og:image:alt" content={title} />
        <meta property="og:url" content={Astro.url}>
        <meta property="article:author" content={author} />
        <meta name="twitter:card" content="summary_large_image">
        <meta name="twitter:site" content={`@${xhandle}`}>
        <meta name="twitter:creator" content={`@${xhandle}`}>

        <link rel="alternate" type="application/rss+xml" title="My Sexy Astro Site" href={`${Astro.site}rss.xml`} />
    </head>

    <body>
        <Header />
        <Nav />
        <slot />
        <Footer />
    </body>
</html>

Make sure the image you specify in the og:image tag exists at that path, and once your site is published you'll see you get a lovely image selected to go with your Facebook/LinkedIn/X/Pinterest/Your Mum's Social Network posts.

If you want to see it in action, you can run them through the Facebook Debugger, the LinkedIn Post Inspector or a more generic tester at OpenGraph.xyz

Wrapping up

We've now got all the basics in place for the site so for completeness here's our final folder structure.

./
├── README.md
├── astro.config.mjs
├── package-lock.json
├── package.json
├── public/
│        └── favicon.svg
├── src/
│        ├── components/
│        │   ├── Footer.astro
│        │   ├── Header.astro
│        │   ├── Nav.astro
│        │   ├── Pagination.astro
│        │   ├── PostDateTime.astro
│        │   ├── PostImage.astro
│        │   ├── PostItem.astro
│        │   ├── TagItem.astro
│        │   └── TagList.astro
│        ├── content/
│        │   ├── config.ts
│        │   └── posts/
│        │       ├── 2024-03-15-my-first-blog-post.mdx
│        │       ├── 2024-03-15-my-second-blog-post.mdx
│        │       └── 2024-03-15-my-third-blog-post.mdx
│        ├── env.d.ts
│        ├── layouts/
│        │   └── Layout.astro
│        └── pages/
│            ├── feed.xml.js
│            ├── index.astro
│            └── posts/
│                ├── [...page].astro
│                ├── [...slug].astro
│                └── tagged/
│                    ├── [tag].astro
│                    └── index.astro
└── tsconfig.json