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:
---
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:
---
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.