## やりたいこと [[🗃️daisyUI]]を使って、ドロップダウンメニューを作成したい ## 調査 - [[🗃️daisyUI]]でドロップダウンのメニューを作る方法は、いくつかある - [Tailwind Dropdown Component — Tailwind CSS Components](https://daisyui.com/components/dropdown/) 1. `<details>`と`<summary>`を使う 2. `<label>`を使う - `<label>`方式だと、キーボード操作での遷移が微妙な動きをする - [[🗃️JavaScript]]での制御方法がいまいち、イメージがつかない の方式の方が、楽な感じがするので1方式で行くことにした。 ## 実装 - 素の状態だといくつか想定した通りの挙動にならなかったので、[[🗃️React]]側で制御を入れることにした ### 課題1 ドロップダウンの外をクリックしてもメニューが閉じない - 想定する挙動としては、別要素をクリックしたときも閉じてほしいが、できない #### 解決策 - [[🗃️Ref(React)]]を使って、制御する - `open`を使って開閉するようにする ### 課題2 ドロップダウンの外をクリックしてもメニューが閉じない - 画面遷移をするアプリケーションであれば問題ないが、 [[🗃️SPA]]になっていたため、差分だけが再レンダリングされて、メニューは開いたままの状態になってしまった #### 解決策 - メニュー内のリンクを押下したときは、`open = false`にして閉じるようにする 最終的に、こんな感じの実装になった。 ```tsx export const Navbar: React.FC = () => { const dropdownRef = useRef<HTMLDetailsElement | null>(null); useEffect(() => { const handleOutsideClick = (e: MouseEvent) => { if ( dropdownRef.current && !dropdownRef.current.contains(e.target as Node) && dropdownRef.current.open ) { dropdownRef.current.open = false; } }; document.addEventListener('click', handleOutsideClick); return () => { document.removeEventListener('click', handleOutsideClick); }; }, []); const handleCloseRefElement = () => { if (dropdownRef.current) { dropdownRef.current.open = false; } }; return ( <header className='bg-base-300 navbar'> <div className='flex-1'> <a href='/' className='text-xl normal-case btn btn-ghost'> App </a> </div> <div className='flex-none'> <ul className='p-0 menu menu-horizontal'> <li> <details ref={dropdownRef}> <summary>Button</summary> <ul className='p-2 bg-base-100'> <li> <a href='/' onClick={handleCloseRefElement}>Link 1</Link> </li> <li> <a href='/' onClick={handleCloseRefElement}>Link 2</Link> </li> </ul> </details> </li> </ul> </div> </header> ); }; ``` - ロジック部分は、 [[🗃️Custom Hooks]]で切り出してあげると良いかも。