Next.js x Chakra UI で新しいタブで開けるメニューを作ってみた

2022.08.30

こんにちは!DA(データアナリティクス)事業本部 サービスソリューション部の大高です。

ウェブサイト上にあるリンクは、通常新しいタブで開くことができます。また、その際には主に以下の3パターンが利用できるかと思います。

  • マウスのホイールボタン(中クリック)でリンクをクリックして開く
  • [Win]Ctrlキー + クリック / [Mac]Commandキー + クリック
  • リンクを右クリックして、コンテキストメニューから「新しいタブで開く」

この機能をNext.jsで利用できるコンポーネントライブラリChakra UIMenuコンポーネントで利用したいと思ったのですが、標準の使い方では利用できず、工夫が必要だったので当エントリで紹介したいと思います。

標準的なMenuコンポーネントの利用

標準的なMenuコンポーネントの利用方法としては、ドキュメントにも利用方法の記載がある通り以下のようになります。

menu-sample.tsx

import { ChevronDownIcon } from '@chakra-ui/icons'
import { Button, Menu, MenuButton, MenuItem, MenuList } from '@chakra-ui/react'
import Link from 'next/link'
import styles from './menu-sample.module.scss'

function MenuSample() {
  return (
    <header className={styles.header}>
      <Menu>
        <MenuButton as={Button} rightIcon={<ChevronDownIcon />} marginLeft={'10px'}>
          普通のメインメニュー
        </MenuButton>

        <MenuList>
          <Link href={'/sample/sub'} passHref>
            <MenuItem>普通のサブメニュー</MenuItem>
          </Link>
        </MenuList>
      </Menu>
    </header>
  )
}

export default MenuSample

menu-sample.module.scss

.header {
  height: 4rem;
  width: 100%;
  background-color: slategrey;
  display: flex;
  align-items: center;
}

シンプルで分かりやすいですね。サブメニューをクリックすることで、リンク先のページに遷移できます。

一方で、これはHTML上ではbuttonspanで構成された要素となるので、リンク先ページを別タブで開くことはできません。

別タブで開けるメニューを作ってみた

上記の問題を解消したものが以下になります。

menu-sample.tsx

import { ChevronDownIcon } from '@chakra-ui/icons'
import { Button, LinkBox, LinkOverlay, Menu, MenuButton, MenuItem, MenuList } from '@chakra-ui/react'
import Link from 'next/link'
import styles from './menu-sample.module.scss'

function MenuSample() {
  return (
    <header className={styles.header}>
      <Menu>
        <MenuButton as={Button} rightIcon={<ChevronDownIcon />} marginLeft={'10px'}>
          普通のメインメニュー
        </MenuButton>

        <MenuList>
          <Link href={'/sample/sub'} passHref>
            <MenuItem>普通のサブメニュー</MenuItem>
          </Link>

          <LinkBox>
            <Link href={'/sample/sub'} passHref>
              <LinkOverlay>
                <MenuItem>別タブで開けるサブメニュー</MenuItem>
              </LinkOverlay>
            </Link>
          </LinkBox>
        </MenuList>
      </Menu>

      <Menu>
        <LinkBox>
          <Link href={'/sample/main'} passHref>
            <LinkOverlay>
              <MenuButton as={Button} marginLeft={'10px'}>
                別タブで開けるメインメニュー
              </MenuButton>
            </LinkOverlay>
          </Link>
        </LinkBox>
      </Menu>
    </header>
  )
}

export default MenuSample

menu-sample.module.scss

.header {
  height: 4rem;
  width: 100%;
  background-color: slategrey;
  display: flex;
  align-items: center;
}

ポイントとして、別タブで開きたいコンポーネントをLinkBoxLinkLinkOverlayで括っています。これにより、HTML上でもa(anchor)タグで括られることになります。

なお、分かりやすくするために上記のように記載していますが、以下のようなコードにしても良いですね。

<LinkBox as={MenuItem}>
  <NextLink href={'/sample/sub'} passHref>
    <LinkOverlay>別タブで開けるサブメニュー</LinkOverlay>
  </NextLink>
</LinkBox>

また、a(anchor)タグで括られたことにより、以下の3つの方法でリンクを新しいタブで開くことが出来るようになりました。

  • マウスのホイールボタン(中クリック)でリンクをクリックして開く
  • [Win]Ctrlキー + クリック / [Mac]Commandキー + クリック
  • リンクを右クリックして、コンテキストメニューから「新しいタブで開く」

実際に画面上で各箇所を右クリックし、コンテキストメニューを表示させたものが以下になります。

「別タブで開けるサブメニュー」と「別タブで開けるメインメニュー」は、ちゃんと「新しいタブで開く」というコンテキストメニューが表示されていますね!

おまけ

別解として以下でも同じようなことが出来ました。一方でこちらはマウスホバー時に「別タブで開けるサブメニュー」の下部にアンダーラインが表示されるので、好みによって使い分けると良いかなと思います。

import { Link, MenuItem } from '@chakra-ui/react'
import NextLink from 'next/link'

<NextLink href={'/sample/sub'} passHref>
  <Link>
    <MenuItem>別タブで開けるサブメニュー</MenuItem>
  </Link>
</NextLink>

まとめ

以上、Next.js x Chakra UI で新しいタブで開けるメニューを作ってみました。

「リンク先を別タブで開きたい」というケースは時々あるので、特に問題がなければこの方法でメニューを作成すると幸せになれるかもしれません。

どなたかのお役に立てば幸いです。それでは!