Gatsby or Theme UI Link
I know this has tripped me up on more than one occasion and if you’re using Theme UI components in your Gatsby project it might have caught you out too.
The problem
The problem is that Gatsby and @theme-ui/components both have a component called Link.
First let’s look at the Gatsby Link
// some-file.js
import { Link } from 'gatsby';
const SomeComponent = () => {
return <Link to='/'>Back to home</Link>;
};
The Gatsby Link uses a to
prop instead of an href
, this is because a Gatsby Link is used to navigate around the
routes in your blog / site / application.
Now let’s look at the Theme UI Link
// some-file.js
import { Link } from '@theme-ui/components';
const SomeComponent = () => {
return <Link href='https://www.paulie.dev'>https://www.paulie.dev</Link>;
};
The Theme UI Link uses an href
attribute which is what you’d normally expect to see on an <a>
and it’s used to
navigate to a URL.
When you look at the import its easy to tell from which library the Link is being imported from but in the usage they look very similar, apart from the difference mentioned above.
We’re also presented with a little problem, suppose you want to navigate to a route and link to a URL in the same component. This requires importing and using both the Link from Gatsby and the Link from Theme UI components…
// some-file.js
import { Link } from 'gatsby';
import { Link } from '@theme-ui/components';
const SomeComponent = () => {
return (
<>
<Link to='/'>Back to home</Link>
<Link href='https://www.paulie.dev'>https://www.paulie.dev</Link>
</>
);
};
❌ … and as you know you can’t import two components with the same name.
The next problem is how to style these links. If you’re familiar with Theme UI you’ll want to use the sx
prop 👇
// some-file.js
import { Link } from 'gatsby';
import { Link } from '@theme-ui/components';
const SomeComponent = () => {
return (
<>
<Link sx={{ color: 'primary' }} to='/'>
Back to home
</Link>
<Link sx={{ color: 'secondary' }} href='https://www.paulie.dev'>
https://www.paulie.dev
</Link>
</>
);
};
… but the Gatsby Link isn’t a Theme UI component so it’s unable to translate the values passed by the sx
prop into
CSS styles. Instead it’ll pass the sx
prop on as an attribute with an odd looking string object thingy.
The rendered DOM node might look like this 👇
<a sx='[object Object]' href='/'>
Back to home
</a>
The solution
First off lets change the way we import the Gatsby Link
// some-file.js
import { Link as GatsbyLink } from 'gatsby';
No it’s easier to determine if we’re looking at a Gatsby Link or a Theme UI Link in both the import statement and in the usage.
Great! we’ve solved one of the problems, but we still want to style these Links using Theme UI.
To achieve this we can cast the Theme UI Link as a GatsbyLink
using the as
prop ✨
// some-file.js
import { Link as GatsbyLink } from 'gatsby';
import { Link } from '@theme-ui/components';
const SomeComponent = () => {
return (
<>
<Link sx={{ color: 'primary' }} to='/' as={GatsbyLink}>
Back to home
</Link>
<Link sx={{ color: 'secondary' }} href='https://www.paulie.dev'>
https://www.paulie.dev
</Link>
</>
);
};
Now we can use the to
prop to navigate around our blog / site / application and we can access all that Theme UI
goodness using the sx
prop.
Pretty sweet ay!