vercel / next.js

The React Framework
https://nextjs.org
MIT License
126.4k stars 26.9k forks source link

You can use className in next/link and many other props. #56488

Closed kasir-barati closed 1 year ago

kasir-barati commented 1 year ago
          You can use className in next/link and many other props.

Originally posted by @kmergen in https://github.com/vercel/next.js/issues/41850#issuecomment-1293907962

Yes, that is right (official doc) but in the LinkProps we do not have it. Look at this code: https://github.com/vercel/next.js/blob/canary/packages/next/src/client/link.tsx#L110C54-L110C54

kevinmitch14 commented 1 year ago

This is expected, next/link accepts props specific to the Next.js implementation but also accepts properties that you would normally find in a HTML anchor tag.

kasir-barati commented 1 year ago

Hmm, So how can I say that here in this code @kevinmitch14 :

import classNames from 'classnames';
import { StaticImport } from 'next/dist/shared/lib/get-img-props';
import Image from 'next/image';
import Link, { LinkProps } from 'next/link';
import { PropsWithChildren } from 'react';

export interface SidebarLinkProps
    extends PropsWithChildren<LinkProps> {
    name: string;
    dataTest?: string;
    isActive?: boolean;
    // README: For some reason even though in the official doc it says that Link component supports className, but apparently in the LinkProps we do not have it: https://nextjs.org/docs/pages/api-reference/components/link#props
    className?: string;
    svgIcon?: string | StaticImport;
}

export function SideBarLink({
    name,
    dataTest,
    isActive,
    svgIcon,
    className,
    ...rest
}: SidebarLinkProps) {
    return (
        <Link data-test={dataTest} className={classNames()} {...rest}>
            {svgIcon && (
                <div className="">
                    <Image
                        alt={name + ' icon'}
                        className={classNames()}
                        src={svgIcon}
                    />
                </div>
            )}
            <span className="">{name}</span>
        </Link>
    );
}

As you see I had to define the className manually. and LinkProps<HTMLAnchorElement> does not work too

kevinmitch14 commented 1 year ago

How about something like this? This should give you all the same props as the <Link /> component and your own custom props on top.

type CustomLinkProps = React.ComponentPropsWithoutRef<typeof Link> & {
  myCustomProp?: string;
  isActive: boolean;
  "data-test"?: string;
};

function CustomLink(props: CustomLinkProps) {
  return <Link {...props} />;
}

And using the Custom Link like so:

<CustomLink
  className="bg-red-400"
  href={"/admin"}
  data-test="testing"
  myCustomProp="hello"
  isActive={true}
/>

className is not a prop on InternalLinkProps. The className prop on next/link comes from the combination of the types below, not solely InternalLinkProps.

declare const Link: React.ForwardRefExoticComponent<Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, keyof InternalLinkProps> & InternalLinkProps & {
    children?: React.ReactNode;
} & React.RefAttributes<HTMLAnchorElement>>;
balazsorban44 commented 1 year ago

Was moved to issues by accident. Please open a bug report if you want to report an issue.

Link does support className as it inherits it from an anchor element: https://github.com/vercel/next.js/blob/canary/packages/next/src/client/link.tsx/#L262

image

You can ask for further TypeScript help in discussions.

github-actions[bot] commented 1 year ago

This closed issue has been automatically locked because it had no new activity for 2 weeks. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.