Skip to content

Instantly share code, notes, and snippets.

@zackdotcomputer
Last active August 27, 2022 15:43
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zackdotcomputer/d7af9901e7db87364aad7fbfadb5c99b to your computer and use it in GitHub Desktop.
Save zackdotcomputer/d7af9901e7db87364aad7fbfadb5c99b to your computer and use it in GitHub Desktop.
Workaround for next/link vs <a> href accessibility lint issue
// Created by Zack Sheppard (@zackdotcomputer) on 1/19/2021
// Freely available under MIT License
// Workaround for https://github.com/vercel/next.js/issues/5533
import Link, { LinkProps } from "next/link";
import { AnchorHTMLAttributes, PropsWithChildren } from "react";
type PropTypes = LinkProps & Omit<AnchorHTMLAttributes<HTMLAnchorElement>, "href">;
/// A unified component for the next/link <Link> and a standard <a> anchor.
/// Will lift href and all other props from Link up to the Link.
/// Will automatically make an <a> tag containing the children and pass it remaining props.
const LinkTo = ({
children,
href,
as,
replace,
scroll,
shallow,
prefetch,
locale,
...anchorProps
}: PropsWithChildren<PropTypes>) => {
return (
// These props are lifted up to the `Link` element. All others are passed to the `<a>`
<Link {...{ href, as, replace, scroll, shallow, prefetch, locale }}>
{/* eslint-disable-next-line react/jsx-props-no-spreading */}
<a {...anchorProps}>{children}</a>
</Link>
);
};
export default LinkTo;
@zackdotcomputer
Copy link
Author

Note: this is written in Typescript 4 for Next 10. ymmv if not on those versions.

@Jak-Ch-ll
Copy link

Hi there,

with typescript in strict mode, the native Link component is throwing an error: Type 'string | undefined' is not assignable to type 'Url'.

I thinkered a bit and came to the following changes:

import Link, { LinkProps } from "next/link";
import { AnchorHTMLAttributes, PropsWithChildren } from "react";

type PropTypes = LinkProps & AnchorHTMLAttributes<HTMLAnchorElement>;

/// A unified component for the next/link <Link> and a standard <a> anchor.
/// Will lift href and all other props from Link up to the Link.
/// Will automatically make an <a> tag containing the children and pass it remaining props.
const LinkTo = ({
  children,
  href,
  as,
  replace,
  scroll,
  shallow,
  prefetch,
  locale,
  ...anchorProps
}: PropsWithChildren<PropTypes>) => {
  return (
    // These props are lifted up to the `Link` element. All others are passed to the `<a>`
    <Link {...{ href, as, replace, scroll, shallow, prefetch, locale }}>
      {/* eslint-disable-next-line react/jsx-props-no-spreading */}
      <a {...anchorProps}>{children}</a>
    </Link>
  );
};

export default LinkTo;

What do you think about this solution? After a few tests, everything seems to work fine, the href is passed correctly to the Link-Component and is rendered into the dom (in dev and build). The LinkTo-Component even typechecks for a href, which your orginal solution does not (at least for me).

@zackdotcomputer
Copy link
Author

@Jak-Ch-ll looks good - I am running this with a subset of strict rather than the whole shebang so I wasn't seeing the error you got. I like your solution of just pulling in the Props from Next rather than trying to clone them, the only change I'm going to make is that I think we should Omit the href key from AnchorHTMLAttributes in our Props union so that we don't wind up confusing the type there. I'll update the gist with that now.

@Jak-Ch-ll
Copy link

@zackdotocomputer ah cool, learned something new. I didn't know about Omit and that's definitly a good idea!

@adriankwiat
Copy link

I have this problem
image

@zackdotcomputer
Copy link
Author

@adriankwiat What versions of Typescript and Next are you using? And what does your tsconfig look like? That is strange but I'm guessing it is a strictness check in typescript that is complaining that TECHNICALLY as?: Url and as: Url | undefined are different (though functionally they are basically the same).

@adriankwiat
Copy link

I see that my VSCode uses dev version of typescript 4.4.0. Changing back to stable 4.3.2 resolved problem. I didn't think about that before

@zackdotcomputer
Copy link
Author

Oof good to know that this might break with 4.4 though

@Igor-Iugin
Copy link

Hi made a similar solution but instead of AnchorHTMLAttributes I used HTMLAttributes. Just wanted to thank you for the solution :D

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment