รูปภาพ cover image จากเว็บ https://headlessui.com/

ทำ Dialog (Modal) ด้วยการใช้ Headless UI + TailwindCSS

React Apr 19, 2023

ตัวอย่างการทำ Dialog หรือ Modal ด้วยการใช้ Tailwind CSS และ Headless UI ซึ่งตัว Headless UI เป็น UI Components รองรับทั้ง React และ Vue สำหรับใครที่ไม่รู้จัก สามารถเข้าไปดูรายละเอียด และตัวอย่างได้ในเว็บเลย มี Component หลายแบบ

Headless UI
Completely unstyled, fully accessible UI components, designed to integrate beautifully with Tailwind CSS.

เริ่มทำ Dialog

สร้างโปรเจ็ค React ขึ้นมา ด้วย Vite + TypeScript

npm create vite@latest headless-modal -- --template react-ts
cd headless-modal
npm install

จากนั้นก็ทำการเพิ่ม Tailwind CSS ลงในโปรเจ็ค

npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p

เพิ่ม content ในส่วน tailwind.config.js

/** @type {import('tailwindcss').Config} */
export default {
  content: [
    "./index.html",
    "./src/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}

เพิ่ม directive ในไฟล์ css src/index.css

@tailwind base;
@tailwind components;
@tailwind utilities;

ติดตั้ง Headless UI

ทำการติดตั้ง Library เพื่อให้ใช้ Headless UI ได้

npm install @headlessui/react

ตัว Dialog Component มี built-in 4 แบบ คือ

  • Dialog - เป็น Component หลักสำหรับ Dialog รับ props เป็น open true หรือ false
  • Dialog.Panel - เป็น Panel หรือ Wrapper ภายใน Dialog
  • Dialog.Title - เป็น title ของ Dialog
  • Dialog.Description - เป็น description ของ Dialog

Code Snippet จากหน้าเว็บของ Headless UI คือแบบนี้ (ลองสร้างไฟล์ components/MyDialog.tsx ขึ้นมา โดยใช้โค๊ดเดียวกับหน้าเว็บ headless ui และก็ปรับ style เล็กๆน้อยๆ

import { useState } from 'react'
import { Dialog } from '@headlessui/react'

function MyDialog() {
  let [isOpen, setIsOpen] = useState(true)

  return (
    <div className="modal">
      <Dialog open={isOpen} onClose={() => setIsOpen(false)}>
        <div className="fixed inset-0 bg-black/30" aria-hidden="true" />

        <div className="fixed inset-0 overflow-y-auto">
          <div className="flex min-h-full container max-w-md mx-auto items-center justify-center p-4">
            <Dialog.Panel as="div" className="p-4 rounded-xl bg-black">
              <Dialog.Title>Deactivate account</Dialog.Title>
              <Dialog.Description>
                This will permanently deactivate your account
              </Dialog.Description>

              <p>
                Are you sure you want to deactivate your account? All of your
                data will be permanently removed. This action cannot be undone.
              </p>

              <button onClick={() => setIsOpen(false)}>Close</button>
            </Dialog.Panel>
          </div>
        </div>
      </Dialog>
      <button onClick={() => setIsOpen(true)}>Open Modal</button>
    </div>
  )
}

export default MyDialog

ลองเพิ่ม component ที่หน้า index ของเราแล้วดูผลลัพธ์

import MyDialog from './components/MyDialog'

// render
<MyDialog />

การ ซ่อน และ แสดง dialog เราจะควบคุมมันด้วยการมใช้ state จะเห็นว่าในตัวอย่าง สร้าง state ขึ้นมาคือ

let [isOpen, setIsOpen] = useState(false)

ตัว Dialog มี 2 props คือ

  • open - ก็รับค่า เป็น true / false ถ้า true คือให้ Dialog แสดง
  • onClose - เป็น function เพื่อ set ให้ isOpen เป็น false เวลา user กดข้างนอก Modal

ทดลอง start dev server และลองดูผลลัพธ์อีกครั้ง

บทความนี้ก็เป็นตัวอย่างการทำ Modal ง่ายๆ สำหรับคนที่ใช้ React และ Tailwind CSS อยู่เป็นประจำ นอกจากนี้ เรายังสามารถประยุกต์ใช้ Modal ได้อีกหลากหลาย เช่น เพิ่ม Transition ให้กับ Dialog (Modal) เป็นต้น

ลองไปเล่นกันดูนะครับ

Happy Coding ❤️

Tags

Chai Phonbopit

เป็น Web Dev ทำงานมา 10 ปีหน่อยๆ ด้วยภาษา JavaScript, Node.js, React, Vue และปัจจุบันกำลังสนใจ Web3, Crypto และ Blockchain เขียนบล็อกที่ https://devahoy.com