next-direction

A Next.js package, that makes working with directions a breeze. - No flash on load (both SSR and SSG) - Sync direction across tabs and windows - Disable flashing when refreshing pages - Force pages to a specific direction

Usage no npm install needed!

<script type="module">
  import nextDirection from 'https://cdn.skypack.dev/next-direction';
</script>

README

next-direction next-direction minzip package size MIT Licence Twitter Follow

A Next.js package, that makes working with directions a breeze.

  • No flash on load (both SSR and SSG)
  • Sync direction across tabs and windows
  • Disable flashing when refreshing pages
  • Force pages to a specific direction

Preview

Check out the Live Example to try it for yourself.

Installation

$ npm install next-direction
# or
$ yarn add next-direction

Usage

  • Add the next-direction Provider to your custom _app
import { DirModeProvider } from "next-direction";

function MyApp({ Component, pageProps }) {
  return (
    <DirModeProvider>
      <Component {...pageProps} />
    </DirModeProvider>
  )
}

export default MyApp

useDirMode

import { useDirMode } from 'next-direction'

const DirmodeChanger = () => {
  const { dirmode, setDirMode } = useDirMode();

  return (
    <div>
      The current direction is: {dirmode}
      <button onClick={() => setDirMode('ltr')}>LTR Mode</button>
      <button onClick={() => setDirMode('rtl')}>RTL Mode</button>
    </div>
  )
}

Warning! The above code is hydration unsafe and will throw a hydration mismatch warning when rendering with SSG or SSR. This is because we cannot know the direction on the server, so it will always be undefined until mounted on the client.

You should delay rendering any direction toggling UI until mounted on the client. See the example.

APIs

DirModeProvider

  • storageKey = 'dirmode': Key used to store dir mode setting in localStorage
  • defaultDirMode = 'ltr': Default dir mode name
  • forcedDirMode: Forced dir mode name for the current page (does not modify saved dir mode settings)

UseDirMode

  • dirmode: Active dir mode name
  • setDirMode(dirmode: string): a function to set the dir mode
  • forcedDirMode: Forced page dir or falsy. If forcedDirMode is set, you should disable any dir mode switching UI

Avoid Hydration Mismatch

Because we cannot know the dirmode on the server, many of the values returned from useDirMode will be undefined until mounted on the client. This means if you try to render UI based on the current dir mode before mounting on the client, you will see a hydration mismatch error.

The following code sample is unsafe:

import { useDirMode } from 'next-direction'

const dirModeChanger = () => {
  const { dirMode, setDirMode } = useDirMode()

  return (
    <div>
      The current direction mode  is: {dirMode}
      <button onClick={() => setDirMode('LTR')}>LTR Mode</button>
      <button onClick={() => setDirMode('RTL')}>RTL Mode</button>
    </div>
  )
}

To fix this, make sure you only render UI that uses the current dir mode when the page is mounted on the client:

import { useDirMode } from 'next-direction'

const DirModeChanger = () => {
  const [mounted, setMounted] = useState(false)
  const { dirMode, setDirMode } = useDirMode()

  // When mounted on client, now we can show the UI
  useEffect(() => setMounted(true), [])

  if (!mounted) return null

  return (
    <div>
      The current direction mode  is: {dirMode}
      <button onClick={() => setDirMode('LTR')}>LTR Mode</button>
      <button onClick={() => setDirMode('RTL')}>RTL Mode</button>
    </div>
  )
}

To avoid Content Layout Shift, consider rendering a skeleton until mounted on the client side.

You might like

I created another plugin that makes working with bi-direction less painful with tailwind, check it out: https://github.com/yassinebridi/tailwind-direction

Credits

This project's code is heavily inspired by this great project