npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

remix-isomorphic-link

v1.1.0

Published

A wrapper component around Remix's Link / NavLink components and the native anchor element. One component to rule them all! Render an anchor tag for outgoing links and a Remix Link / NavLink for everything else! Also supports automated final slashes for a

Downloads

14

Readme

Remix Isomorphic Link

One Component to rule them all links!

This packages provides a single isomorphic link component that wraps around Remix's NavLink component and the native anchor tag. It provides a simple API to manage both outgoing and internal hrefs through one component!

Note: This package is a "fork" of react-router-isomorphic-link that adds support for the ressource prefetching features of Remix.

Installation

npm

npm i remix-isomorphic-link

yarn

yarn add remix-isomorphic-link

When to use this package?

TL;DR: This packages is inteded to support uniform handling and styling of all links within one component.

Limitations of Remix

Remix's Link component does not support outgoing hrefs or URLs to internal pages.

import { Link } from '@remix-run/react';

function MyComponent() {
  return (
    <>
      <Link to="/contact">Internal absolute path</Link>
      <Link to="contact">Internal relative path</Link>
      Won't work: <Link to="https://hosted-domain.com/contact">URL to internal absolute path</Link>
      Won't work: <Link to="youtube.com">Outgoing href</Link>
      Won't work: <Link to="https://youtube.com">Outgoing URL</Link>
      Won't work: <Link to="mailto:[email protected]">Non-http protocol href</Link>
    </>
  );
}

Sometimes you have to dynamically map hrefs to a link component. If your hrefs include both internal and external locations, it can be hard to make it work with Remix's Link component. Most likely, you will need to write custom logic. This is what this packages does for you!

Links in Markdown

To give you one example, whenever I work with MDX or Markdown, I find myself using internal paths, outgoing/external URLs, and sometimes even internal links that include my domain in the same markdown file.

# Welcome to my documentation

Go to the [dashboard](https://my-cool-site.com/dashboard#create) to create a new project.

If you have questions, please contact us via [email](mailto:[email protected]) or [on Twitter](https://twitter.com/my-cool-site).

I mostly use rehype to map Markdown to custom React components. Unfortunately, Remix's Link component does not support outgoing links or full URLs to internal pages. So I find myself repeatedly creating small wrappers around the Link component.

The first href is a "full" URL to an internal page, the second should be handled as an email address, and the third one is a URL to an external website. I want all them links to work in Markdown previews (like on GitHub or VS Code) and within my application. That's what Remix Isomorphic Link is intended for!

Feedback & Issues

Please provide your feedback on GitHub!

Versions

  • Version 0.x.x implements the inital version of the IsomorphicLink link component and the useIsomorphicNavigate hook in TypeScript.

Changelog

👀

Usage

This package exposes the following utilities:

  • IsomorphicLink component
  • useIsomorphicNavigate hook
  • IsomorphicNavProvider context provider
  • isomorphicClassName function
  • isomorphicStyle function

And the following TypeScript types:

  • IsomorphicLinkProps
  • IsomorphicNavContextProps
  • IsomorphicNavigateFunction

IsomorphicLink

Supported features and how it works:

  • Supports all Remix's NavLink props.
  • Guesses if the supplied to prop is internal or external.
  • Allows explicit override via isExternal prop.
  • Utilizes config options from the IsomorphicNavContext.

Optional: Configuration via the IsomorphicNavProvider

Use the IsomorphicNavProvider to provide configuration options to the IsomorphicLink component:

import { IsomorphicNavProvider } from 'remix-isomorphic-link';
const host = process.env.NODE_ENV === 'production' ? 'your-domain.com' : 'localhost:3000';

const App = () => {
  return (
    <IsomorphicNavProvider host={host} defaultPrefetch="intent" useTrailingSlash openOutgoingAsBlank>
      ...
    </IsomorphicNavProvider>
  );
};
  • host prop: Make sure to provide your host, so IsomorphicLink can strip your domain from internal pathnames to support SPA routing through Remix!
  • useTrailingSlash prop: Some hosts (like Netlify) redirect all paths to a path with a trailing slash. Set this to true to automatically add a trailing slash to internal paths to avoid redirects. Defaults to false, which will not add a trailing slash to internal paths.
  • openOutgoingAsBlank prop: Set a policy to open all identified outgoing links in a new tab/window. Defaults to false, which will open outgoing links in the same tab/window.
  • defaultPrefetch prop: Set a policy to prefetch all identified internal links using Remix's prefetch feature. Defaults to none (default in Remix), which will not prefetch outgoing links.

How to best pass the host to IsomorphicNavProvider?

Kent uses this neat function to calculate the domain URL of an application. We can adapt the function a little to get the current host.

export function getHost(request: Request) {
  const host = request.headers.get('X-Forwarded-Host') ?? request.headers.get('host');
  if (!host) {
    throw new Error('Could not determine domain host.');
  }
  return host;
}

export function loader({ request }: LoaderArgs) {
  const host = getHost(request);
  return { host };
}

export default function Root() {
  const { host } = useLoaderData();
  return (
    <IsomorphicNavProvider host={host}>
      ...
    </IsomorphicNavProvider>
  );
}
```

#### isExternal prop

IsomorphicLink component is able identify external URLs and will render a native anchor element instead of the Remix Link component:

```jsx
import { IsomorphicLink } from 'remix-isomorphic-link';

function MyComponent() {
  return <IsomorphicLink to="https://youtube.com">YouTube</IsomorphicLink>;
}

However, you can also explicitly tell IsomorphicLink to use or not use a native anchor tag for a link:

import { IsomorphicLink } from 'remix-isomorphic-link';

function MyComponent() {
  return (
    <IsomorphicLink to="youtube.com" isExternal>
      YouTube
    </IsomorphicLink>
  );
}

In this case, IsomorphicLink won't guess but just follow the isExternal prop.

Note: You must use valid URLs (including the protocol e.g., https) for outgoing hrefs if you want to omit the isExternal property. Otherwise, IsomorphicLink will treat your external href as an internal relative path (youtube.com vs. index.html).

Styling

You can use the NavLink className and style prop to style your link. Note that you can pass a function to both properties as documented in the React Router documentation. Note that for IsomorphicLink, active will always be false in case your href is outgoing.

Additionally, IsomorphicLink specifies two additional classes that you can use to differ the styling of your outgoing and internal links.

  • "isomorphic-link" supplied to all links.
  • "isomorphic-link--internal" is only supplied to internal links.
  • "isomorphic-link--external" is only supplied to outgoing links.

isomorphicClassName & isomorphicStyle utilities

The isomorphicClassName and isomorphicStyle utilities are handy if you create further abstraction layers around the IsomorphicLink component and want to be able to make use of the className function property of React Router's NavLink component.

As visible in the example, we wrap IsomorphicLink in a custom component, which itself might be wrapped in a higher order StyledLink component. The isomorphicClassName function is used to process the className prop in each of these higher order components to make sure both cases (string and func) are handeled correctly.

import type { IsomorphicLinkProps } from 'remix-isomorphic-link';
import { IsomorphicLink, isomorphicClassName } from 'remix-isomorphic-link';

type UnstyledLinkProps = {
  outline?: 'normal' | 'small' | 'none';
} & IsomorphicLinkProps;

const UnstyledLink: FC<PropsWithChildren<UnstyledLinkProps>> = ({
  to,
  outline = 'small',
  children,
  className = '', // Note: className can again be a function and isomorphicClassName will make sure the function is called with the active prop.
  ...props
}) => {
  return (
    <IsomorphicLink
      {...props}
      to={to}
      className={({ isActive }) =>
        `${outline === 'none' ? '' : getAriaClasses(outline === 'small')} ${isomorphicClassName(className, active)}`
      }
    >
      {children}
    </IsomorphicLink>
  );
};