Linkについて - React Ariaの実装読むぞ
こんにちは、フロントエンドエンジニアの mehm8128 です。
今日は Link について書いていきます。
useLinkとは
リンクを作るための hook です。
使用例
ドキュメントからそのまま取ってきています。
function Link(props) {
let ref = React.useRef(null);
let { linkProps } = useLink(props, ref);
return (
<a {...linkProps} ref={ref} style={{ color: "var(--blue)" }}>
{props.children}
</a>
);
}
本題
APG はこちらです。
リンクを disabled にする方法
useLink内部で昨日紹介したusePressを利用しているのですが、useLinkにisDisabledを渡すとusePress内でe.preventDefault()してくれて、ナビゲーションが発火しないようになります。
これによって disabled が実現されています。
client side navigation
useLinkを用いると、例えば Next.js のrouter.push()などの client side navigation が a タグをクリックしたときに実行されるようになります。つまり、Next.js のLinkコンポーネントのような動きをすることになります。
こちらのページに詳細が書かれています。
実現方法としては上記のページに書かれているような方法でRouterProviderのnavigateprops にrouter.pushなどのナビゲーション関数を登録すると、useLink内部で以下のようにRouterProviderの context からrouterを取得しています(このuseRouterは React Aria 独自のものです)。
そして、useLinkの linkProps を渡した要素のonClickでe.preventDefault()して、router.open()(navigate関数の発火などが含まれているメソッド)が実行され、無事 client side navigation が実現されています。
useLinkで足りないもの
色々と面倒を見てくれるuseLinkですが、どうしても実現できないものもあります。
以下のリンクの「note」を見てください。
Authors are strongly encouraged to use a native host language link element, such as an HTML <A> element with an href attribute. As with other WAI-ARIA widget roles, applying the link role to an element will not cause browsers to enhance the element with standard link behaviors, such as navigation to the link target or context menu actions. When using the link role, providing these features of the element is the author's responsibility.
a タグのリンクを使うとき、ブラウザはいくつか便利機能を提供してくれています。
例えば Chrome の場合、リンクにホバーしたとき、左下に小さく URL が表示されます。また、リンクの上で右クリックしたときのコンテキストメニューに「新しいタブで開く」などの項目があったり、中クリックしても新しいタブでリンク先のページを開くことができたりします。
しかし、spanタグでリンクを実装してuseLinkを利用した場合、aタグではないため、ブラウザはこれらの機能を提供してくれません。
以下のページの Example では、リンクがaタグ以外のタグで実装されています。上で挙げた機能が提供されていないことを確認してみてください。
よって、リンクはできるだけaタグで実装するのが好ましいです。
リンクがドラッグできないバグ
こんな issue がありました。
普通aタグはdraggable="false"がついていない限りドラッグすることができて、ブラウザ上部に持っていくことで別タブで開いたり、テキスト入力欄に持っていくと URL をそのままペースト(?)できたりするのですが、useLinkを使っているとなぜかドラッグできなくなってしまうというバグらしいです。
そこで僕が調査して、一応修正 PR を出すところまでいったのですがまだ見てもらえていません。直ってはいるけど修正のしかたに自信がないので、レビューとかもらえると助かります。
原因としてはusePressでe.preventDefault()したくないところでもされてしまっていたので、そこをいい感じに直しました。
まとめ
明日の担当は @mehm8128 さんで、 Text Field についての記事です。お楽しみにー
Discussion