ガイド

構成

asChild プロップを使用して、Radix の機能を代替要素タイプまたは独自の React コンポーネントに合成します。

DOM 要素をレンダリングするすべての Radix プリミティブパーツは、asChild プロップを受け入れます。asChildtrue に設定されている場合、Radix はデフォルトの DOM 要素をレンダリングせず、代わりにパーツの子を複製して、機能させるために必要なプロップと動作を渡します。

要素タイプの変更

ほとんどの場合、Radix は最適なデフォルトを提供するように設計されているため、要素タイプを変更する必要はありません。ただし、そうすることが役立つ場合もあります。

良い例は Tooltip.Trigger です。デフォルトでは、この部分は button としてレンダリングされますが、リンク(a タグ)にもツールチップを追加したい場合があります。asChild を使用してこれを実現する方法を見てみましょう。

import * as React from 'react';
import * as Tooltip from '@radix-ui/react-tooltip';
export default () => (
<Tooltip.Root>
<Tooltip.Trigger asChild>
<a href="https://radix-ui.dokyumento.jp/">Radix UI</a>
</Tooltip.Trigger>
<Tooltip.Portal></Tooltip.Portal>
</Tooltip.Root>
);

基礎となる要素タイプを変更することにした場合、アクセシビリティと機能を維持する責任はあなたにあります。Tooltip.Trigger の場合、ポインターイベントとキーボードイベントに対応できるフォーカス可能な要素である必要があります。div に切り替えると、アクセシビリティが失われます。

実際には、上記のように基礎となる DOM 要素を変更することはほとんどありません。代わりに、独自の React コンポーネントを使用することが一般的です。これは、デザインシステムのカスタムボタンやリンクと機能を合成したいことが多いため、ほとんどの Trigger パーツに当てはまります。

独自の React コンポーネントとの合成

これは上記と同じように機能します。パーツに asChild を渡し、独自のコンポーネントでそれをラップします。ただし、注意すべき点がいくつかあります。

コンポーネントはプロップを展開する必要があります

Radix があなたのコンポーネントを複製するとき、機能的でアクセシブルにするために独自の props とイベントハンドラーを渡します。あなたのコンポーネントがそれらの props をサポートしていない場合、動作が停止します。

これは、すべて prop を基礎となる DOM ノードに展開することによって行われます。

// before
const MyButton = () => <button />;
// after
const MyButton = (props) => <button {...props} />;

実装の詳細(どの props/イベントを受け入れるかなど)を気にする必要がないようにするため、常にこれを行うことをお勧めします。「リーフ」コンポーネント全般において、これは良い習慣だと考えています。

要素の種類を直接変更する場合と同様に、カスタムコンポーネントによってレンダリングされる要素の種類がアクセシビリティと機能性を維持していることを確認するのは、あなたの責任です。

あなたのコンポーネントはrefを転送する必要があります。

さらに、Radixは場合によっては、refをあなたのコンポーネントにアタッチする必要があります(例えば、サイズを測定するため)。あなたのコンポーネントがrefを受け付けない場合、動作しなくなります。

これはReact.forwardRefを使用して行われます(詳細はreact.devを参照)。

// before
const MyButton = (props) => <button {...props} />;
// after
const MyButton = React.forwardRef((props, forwardedRef) => (
<button {...props} ref={forwardedRef} />
));

これはすべての部分に必要というわけではありませんが、実装の詳細を気にする必要がないように、常にこれを行うことをお勧めします。これは、リーフコンポーネントに対しても一般的に良いプラクティスです。

複数のプリミティブの合成

asChildは必要に応じて深く使用できます。これは、複数のプリミティブの動作を組み合わせるための優れた方法です。Tooltip.TriggerDialog.Triggerを独自のボタンと組み合わせて使用する方法の例を以下に示します。

import * as React from 'react';
import * as Dialog from '@radix-ui/react-dialog';
import * as Tooltip from '@radix-ui/react-tooltip';
const MyButton = React.forwardRef((props, forwardedRef) => (
<button {...props} ref={forwardedRef} />
));
export default () => {
return (
<Dialog.Root>
<Tooltip.Root>
<Tooltip.Trigger asChild>
<Dialog.Trigger asChild>
<MyButton>Open dialog</MyButton>
</Dialog.Trigger>
</Tooltip.Trigger>
<Tooltip.Portal></Tooltip.Portal>
</Tooltip.Root>
<Dialog.Portal>...</Dialog.Portal>
</Dialog.Root>
);
};