🐟

mantineでaタグの中にaタグを入れるとエラーが出た

に公開

エラーが出る理由

mantineを使っていると以下のようにCardをリンクにしつつ、中にボタンのリンクを入れたくなる時があると思います。(今回の場合はNextなのでLink)

import { Card, Button } from "@mantine/core";
import Link from 'next/link'

<Card component={Link}>
	<Button component={Link}>
		詳細
	</Button>
</Card>

しかし、これはHTMLの仕様上許されておらずNext.jsなどでは以下のエラーが出ます。aタグはインタラクティブコンテンツのため入れ子にすることが許可されていません。

In HTML, <a> cannot be a descendant of <a>. This will cause a hydration error.

https://developer.mozilla.org/ja/docs/Web/HTML/Reference/Elements/a#技術的概要

回避方法

aタグを並列化する

maintineの Overlayコンポーネントを使い下記のように並列化を行うとエラーは起きなくなります。
https://mantine.dev/core/overlay/

import { Card, Button } from "@mantine/core";
import Link from 'next/link'

<Card>
	<Button component={Link}>
		詳細
	</Button>
	
	<Overlay
		component={Link}
		zIndex={1}
    opacity={0}
	 />
</Card>

Overlayが正常に重ならない場合

Menu.Dropdown コンポーネント内のMenu.Item など一部親要素までOverlay の影響範囲になってしまう場合があります。
この場合Overlayを使わずにLink に対してCSSで調整する必要ががあります。

<Menu.Dropdown>
	<Menu.Item>
		<Button component={Link}>
			詳細
		</Button>
		<Overlay
			component={Link}
			zIndex={1}
	    opacity={0}
	  /> // 親要素全体までOverlayしてしまう
	</Menu.Item>
</Menu.Dropdown>

下記のような形でOverlay コンポーネントを辞め、Linkに対してCSSを当てると回避できます。
menuクラスをposition:relativeで範囲指定して、その中のlinkクラスをposition:absoluteで親コンポーネント(ここではMenu.Item)の範囲限界まで広げます。
これでリンクの中にリンクがあるという挙動を再現できます。

<Menu.Dropdown>
	<Menu.Item className="menu">
		<Link  className="link"/>
		<Button component={Link}>
			詳細
		</Button>
	</Menu.Item>
</Menu.Dropdown>
.menu {
  position: relative;
}

.link {
  position: absolute;
  left: 0px;
  z-index: 1;
  width: 100%;
  height: 100%;
}
GitHubで編集を提案
SMARTCAMP Engineer Blog

Discussion