Skip to main content

Conditional Link

Component that can differentiate between internal link or new tab link

––– views

Usage

This component will detect your href props, if it starts with https://, it will direct you to another tab. If it starts with / it will use Next.js / React Router Link Component.

Next.js Code:

// components/UnstyledLink.tsx
import clsx from 'clsx';
import Link, { LinkProps } from 'next/link';
 
export type UnstyledLinkProps = {
  href: string;
  children: React.ReactNode;
  openNewTab?: boolean;
  className?: string;
} & React.ComponentPropsWithoutRef<'a'> &
  LinkProps;
 
export default function UnstyledLink({
  children,
  href,
  openNewTab,
  className,
  ...rest
}: UnstyledLinkProps) {
  const isNewTab =
    openNewTab !== undefined
      ? openNewTab
      : href && !href.startsWith('/') && !href.startsWith('#');
 
  if (!isNewTab) {
    return (
      <Link {...rest} className={className} href={href}>
          {children}
      </Link>
    );
  }
 
  return (
    <a
      target='_blank'
      rel='noopener noreferrer'
      href={href}
      {...rest}
      className={clsx(className, 'cursor-newtab')}
    >
      {children}
    </a>
  );
}

Create React App Code:

For Create React App with React Router, we need to use Link component from react router

// components/UnstyledLink.jsx
import { Link } from 'react-router-dom';
 
export default function UnstyledLink({
  href,
  className = '',
  openNewTab,
  children,
  ...rest
}) {
  const isInternalLink = href && (href.startsWith('/') || href.startsWith('#'));
 
  // If is internal link, and no override specified
  if (isInternalLink && openNewTab === undefined) {
    return (
      <Link to={href} className={className}>
        {children}
      </Link>
    );
  }
 
  // If no override then _blank
  // if there is override then use the boolean
  return (
    <a
      href={href}
      className={className}
      target={openNewTab === undefined || openNewTab ? '_blank' : undefined}
      rel='noopener noreferrer'
      {...rest}
    >
      {children}
    </a>
  );
}

Custom Style

To add some classes, I usually make another component such as buttons, hover links, etc.

import UnstyledLink from './UnstyledLink';
 
export default function CustomLink({ className = '', ...rest }) {
  return (
    <UnstyledLink
      {...rest}
      className={`inline-flex items-center font-bold hover:text-primary-400 ${className}`}
    />
  );
}