🐟
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.
回避方法
aタグを並列化する
maintineの 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%;
}
Discussion