Fixing Extra Whitespace in Astro Components

Inline components in Astro can introduce unwanted spaces in the rendered HTML. Here’s how wrapping a custom link component in a fragment removed the extra whitespace.

A few months ago, I switched this blog from Next.js to Astro. I like the extra control Astro gives me. While I still enjoy working with React and TSX, Astro is simply a better fit for this particular project.

The migration went smoothly. I was able to port all my components from React to Astro without any major issues.

The Whitespace Problem

After the migration, I noticed something strange: extra whitespace around some of my <Link> components. At first, I didn’t think much of it – browsers often ignore extra spaces in the markup.

For example, Astro generated something like this:

Lorem impsum <a href="/">dolor</a>  sit amet.

See that space after the link? It doesn’t usually show up, so it’s easy to miss. But when the link is at the end of a sentence, things change:

Lorem impsum <a href="/">dolor</a> .

Now, the space becomes visible, and it looks awkward.

The Link Component

Here’s the simplified version of the Link.astro component I was using:

Link.astro
---
import type { HTMLAttributes } from 'astro/types';
import { IS_PROD } from '../contants';

type Props = HTMLAttributes<'a'> & {
  prefetch?: boolean;
};

const { prefetch = true, ...props } = Astro.props;
---

<a {...props} data-prefetch={IS_PROD ? prefetch : undefined}><slot /></a>

<script>
  document
    .querySelectorAll('a[href][data-prefetch="true"]')
    .forEach((link) => { /* prefetch logic */ });
</script>

Nothing fancy, just a basic anchor element and a prefetch script. Astro extracts the script, so it is only included once on the page. The component itself worked fine only that whitespace annoyed me.

I spent quite some time searching through Astro issues (this one looked promising: #6011). Nothing worked. At one point, I even tried rendering the component into a variable and trimming the result.

The Fix: Using a Fragment

Then, I had an idea: what if I wrap the anchor in a fragment (<>...</>)? Aaand, it worked!

Here's the updated Link component:

Link.astro
---
import type { HTMLAttributes } from 'astro/types';
import { IS_PROD } from '../contants';

type Props = HTMLAttributes<'a'> & {
  prefetch?: boolean;
};

const { prefetch = true, ...props } = Astro.props;
---

<>
  <a {...props} data-prefetch={IS_PROD ? prefetch : undefined}><slot /></a>
</>

<script>
  document
    .querySelectorAll('a[href][data-prefetch="true"]')
    .forEach((link) => { ... });
</script>

By wrapping the <a> tag in a fragment, the extra whitespace is gone. Problem solved.