Looking for the best way to create "styled" Gatsby Link
& Theme UI "Link" component
#1202
Replies: 4 comments
-
🤦♂️ now of course when I restarted my Storybook, the correct styles appeared. I would be keen to see if anyone else has a better solution to this though.. |
Beta Was this translation helpful? Give feedback.
-
Hey Zander 👋 Not sure if it's helpful, but I'm using the following in Next. I ditched the Link from @theme-ui/components and I pick the variant manually, but you could as well use ThemeUILink instead of import { Link as BaseLink, LinkProps as BaseLinkProps } from "next-next-link";
import { ExactTheme, useTheme } from "./theme";
export interface LinkProps extends BaseLinkProps {
variant?: "button" | "buttons.secondary" | keyof ExactTheme["links"];
}
export const Link = ({ variant, sx, ...rest }: LinkProps) => {
// links can use variants from `theme.links`, "button" and "buttons.secondary"
const { theme } = useTheme();
const variantStyles =
variant === undefined
? {}
: variant === "button"
? theme.buttons.primary
: variant === "buttons.secondary"
? theme.buttons.secondary
: theme.links[variant];
const styles = sx
? {
...variantStyles,
...sx,
}
: variantStyles;
// external URLs are mapped to `a` instead of Next `Link`
if (
typeof rest.href === "string" &&
rest.href.match(/^(https?:|\/\/|#|mailto:|javascript:)/)
) {
return <a sx={styles} {...rest} href={rest.href as string} />;
}
return <BaseLink sx={styles} {...rest} />;
}; I have similar if statement in my blog. /** @jsx jsx */
import { jsx } from "theme-ui";
import { theme } from "./index";
const components = {
a: (props: ComponentPropsWithoutRef<"a">) => {
if (
!props.href ||
props.href.match(/^(https?|\/\/|#|mailto:|javascript:)/)
) {
// eslint-disable-next-line jsx-a11y/anchor-has-content
return <a sx={theme.styles.a} {...props} />;
}
const { href, ...rest } = props;
return <Link sx={theme.styles.a} to={href} {...rest} />;
}
} I find the Link from @theme-ui/components useful in scenarios where you can't have any routing logic inside of a reusable Link component. I have one example — A Next.js blog and an SPA with React Router inside share UI components, so Link usage basically looks like this <Link
href={href}
onClick={e => {
e.preventDefault();
navigate(href);
}}
{...otherProps}
/> or <Link {...useClientsideLink('/somewhere')} {...otherProps} /> So uhh... I have no solution :D import { ThemedGatsbyLink } from 'somewhere' Do you think it's a common case? |
Beta Was this translation helpful? Give feedback.
-
@mrmartineau I used to have the same approach as you, but my now preferred way is to take advantage of the Emotion's Using this prop you can use any of your themed components and pass in the right "base component". <ThemeLink as={Link} to="/that-page">
This is a link
</ThemeLink>
<Button as={Link} to="/that-page">
This is a link
</Button>
<Button as="a" href="/that-page" target="_blank">
This is a tag
</Button> |
Beta Was this translation helpful? Give feedback.
-
Here's a pure TypeScript take. Note that this doesn't try to combine outbound link functionality; I strongly prefer that as a separate component, since it has a very different purpose. import type { GatsbyLinkProps } from "gatsby";
import { Link as GatsbyLink } from "gatsby";
import type { FC } from "react";
import { forwardRef } from "react";
import type { LinkProps as ThemeLinkProps } from "theme-ui";
import { Link as ThemeLink } from "theme-ui";
type LinkProps = Omit<ThemeLinkProps, "as" | "href"> & AsLinkProps;
type AsLinkProps = Omit<GatsbyLinkProps<unknown>, "ref" | "activeClassName">;
export const Link = forwardRef<HTMLAnchorElement, LinkProps>(function Link(
props,
ref
) {
return <ThemeLink ref={ref} variant="default" {...props} as={AsLink} />;
});
const AsLink: FC<AsLinkProps> = (props) => (
<GatsbyLink activeClassName="active" {...props} />
); |
Beta Was this translation helpful? Give feedback.
-
I am trying, unsuccessfully, to create a new
Link
component that uses either Gatsby'sLink
or Theme UI'sLink
component based on whether the link path is internal or external to the site.I think the bulk of this code came from a Gatsby's own documentation, but now has Theme UI's
Link
added as well.Example usage:
I would love to know if anyone has solved this, and if so, could they share their implementation?
The Theme UI
Link
works, but the GatsbyLink
(GatsbyLink
) does not 🐛Here's my take.
As you can see, I have set a default to use the
styles.a
variant styles if nothing was set. Which means that, in order to change thevariant
, it would need to be overwritten like so:Beta Was this translation helpful? Give feedback.
All reactions