๐๐ป ์๋๋ Dropdown Menu ๋ถ๋ถ์
๋๋ค.
The section below is the dropdown menu.
๐๐ป ๋ ์ด์์, ํฐํธ์ฌ์ด์ฆ๋ ๋๋ถ๋ถ์ css,tailwindcss ๋ด์ฉ์ ์ด์ ํฌ์คํธ์ ๋ด์ฉ๊ณผ ๊ฑฐ์ ์ ์ฌํฉ๋๋ค.
The layout, font size, and most of the CSS and Tailwind CSS details are nearly identical to those in the previous post.
๐๐ป ์ปดํฌ๋ํธ ํ์์ผ๋ก ์ฌ์ฉํ ์ ์๋๋ก ui๋๋ ํ ๋ฆฌ๊ฐ ์ถ๊ฐ๋์์ต๋๋ค.
A ui directory has been added to enable usage in component form.
๐ ํ๋ก์ ํธ ๊ตฌ์กฐ / Project Structure
tailwindcss-nextjs/
โโโ app/
โโโ button-css/
โโโ button-tailwind/
โโโ card-css/
โโโ card-tailwind/
โโโ form-css/
โโโ form-tailwind/
โโโ dropdown-css/
โโโ dropdown-tailwind/
โโโ ui/
โโโ page.tsx
โโโ _components/
โโโ button.tsx
โโโ dropdown.tsx
๐ Dropdown Menu – Tailwind & CSS
โ๏ธ Tailwind
— ์คํฌ๋ฆฐ ์ท / Screen Shoot

— http://localhost:3000/dropdown-tailwind
'use client'
import { useState } from 'react'
const OPTIONS = [
{ value: '9s', label: '9S' },
{ value: '2b', label: '2B' },
{ value: '4b', label: '4B' },
]
export default function Page() {
const [open, setOpen] = useState(false)
const [value, setValue] = useState(OPTIONS[0])
return (
<main className="min-h-screen flex items-center justify-center bg-gray-50 p-4">
<div className="w-full max-w-sm bg-white rounded-2xl shadow-lg p-6">
<h2 className="text-base font-bold">๋๋กญ๋ค์ด/Drop down(Tailwindcss)</h2>
<p className="text-sm text-gray-400 mt-1">freelifemakers</p>
<div className="mt-6 flex flex-col gap-1.5">
<label className="text-sm font-bold text-gray-700">์ง์
/ Role</label>
{/* Select */}
<div className="relative">
{/* 1. ๋ฒํผ - ํญ์ ๋ณด์ด๋ ๋ถ๋ถ / Button - Always visible part */}
<button
onClick={() => setOpen(!open)}
className="w-full flex items-center justify-between px-4 py-3 bg-gray-50 border border-gray-200 rounded-xl text-sm text-left focus:outline-none focus:ring-2 focus:ring-blue-500 focus:bg-white transition-all"
>
<span>{value.label}</span>
<span className={`transition-transform ${open? 'rotate-180' : ''}`}>โผ</span>
</button>
{/* 2. ๋ฆฌ์คํธ - open์ผ ๋๋ง ๋ณด์ด๋ ๋ถ๋ถ / List โ section visible only when open */}
{open && (
<div className="absolute z-10 mt-2 w-full bg-white border border-gray-200 rounded-xl shadow-lg overflow-hidden">
{OPTIONS.map((opt) => (
<button
key={opt.value}
onClick={() => {
setValue(opt)
setOpen(false)
}}
className={`w-full text-left px-4 py-3 text-sm hover:bg-gray-50 transition-colors ${
value.value === opt.value? 'bg-blue-50 text-blue-600 font-bold' : 'text-gray-700'
}`}
>
{opt.label}
</button>
))}
</div>
)}
</div>
<p className="text-xs text-gray-400 mt-2">์ ํ๋ ๊ฐ/Selected Value : {value.value}</p>
</div>
</div>
</main>
)
}
โ๏ธ CSS
— ์คํฌ๋ฆฐ ์ท / ScreenShot

— http://localhost:3000/dropdown-css
'use client'
import { useState } from 'react'
const OPTIONS = [
{ value: '9s', label: '9S' },
{ value: '2b', label: '2B' },
{ value: '4b', label: '4B' },
]
export default function Page() {
const [open, setOpen] = useState(false)
const [value, setValue] = useState(OPTIONS[0])
return (
<>
<main className="page">
<div className="card">
<h2 className="title">๋๋กญ๋ค์ด/Drop down(CSS)</h2>
<p className="subtitle">freelifemakers</p>
<div className="field-group">
<label className="label">์ง์
/ Role</label>
{/* Select ๋ณธ์ฒด - relative ๊ธฐ์ค์ */}
<div className="select-wrap">
{/* 1. ๋ฒํผ */}
<button
onClick={() => setOpen(!open)}
className="select-btn"
>
<span>{value.label}</span>
<span className={`arrow ${open? 'arrow-open' : ''}`}>โผ</span>
</button>
{/* 2. ๋ฆฌ์คํธ */}
{open && (
<div className="select-list">
{OPTIONS.map((opt) => (
<button
key={opt.value}
onClick={() => {
setValue(opt)
setOpen(false)
}}
className={`select-option ${value.value === opt.value? 'selected' : ''}`}
>
{opt.label}
</button>
))}
</div>
)}
</div>
<p className="hint">์ ํ๋ ๊ฐ/Selected Value : {value.value}</p>
</div>
</div>
</main>
<style>{`
.page {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background: #f9fafb;
padding: 16px;
}
.card {
width: 100%;
max-width: 384px;
background: white;
border-radius: 16px;
box-shadow: 0 10px 15px rgba(0,0,0,0.1);
padding: 24px;
}
.title { font-size: 16px; font-weight: 700; }
.subtitle { font-size: 14px; color: #9ca3af; margin-top: 4px; }
.field-group {
margin-top: 24px;
display: flex;
flex-direction: column;
gap: 6px;
}
.label {
font-size: 14px;
font-weight: 700;
color: #374151;
}
.hint {
font-size: 12px;
color: #9ca3af;
margin-top: 8px;
}
/* Dropdown ๊ธฐ์ค์ / benchmark - relative */
.select-wrap {
position: relative;
}
/* 1. ๋ฒํผ / button- w-full flex justify-between */
.select-btn {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px 16px;
background: #f9fafb;
border: 1px solid #e5e7eb;
border-radius: 12px;
font-size: 14px;
text-align: left;
cursor: pointer;
transition: all 0.15s;
}
.select-btn:focus {
outline: none;
background: white;
border-color: #3b82f6;
box-shadow: 0 0 0 2px rgba(59,130,246,0.3);
}
/* ํ์ดํ ํ์ / Rotate arrow */
.arrow {
transition: transform 0.2s;
font-size: 12px;
}
.arrow-open {
transform: rotate(180deg);
}
/* 2. ๋ฆฌ์คํธ / List - absolute z-10 mt-2 */
.select-list {
position: absolute;
z-index: 10;
margin-top: 8px;
width: 100%;
background: white;
border: 1px solid #e5e7eb;
border-radius: 12px;
box-shadow: 0 10px 15px rgba(0,0,0,0.1);
overflow: hidden;
}
/* ์ต์
ํ๋ / One option */
.select-option {
width: 100%;
text-align: left;
padding: 12px 16px;
font-size: 14px;
border: none;
background: white;
color: #374151;
cursor: pointer;
transition: background 0.15s;
}
.select-option:hover {
background: #f9fafb;
}
.select-option.selected {
background: #eff6ff;
color: #2563eb;
font-weight: 700;
}
`}</style>
</>
)
}
๐ ์ปดํฌ๋ํธ ํ์์ผ๋ก ์ฌ์ฉํ๊ธฐ / Using as a component
— ์คํฌ๋ฆฐ ์ท / ScreenShot

— http://localhost:3000/ui
โ๏ธ ํ์ฌ ๋ฒํผ๊ณผ ๋๋กญ๋ค์ด ๋ฉ๋ด๊ฐ _compoents์ ์์ต๋๋ค.(button.tsx dropdown.tsx)
Currently, the button and dropdown menu are located in _components (button.tsx, dropdown.tsx).
โ๏ธ app/ui/page.tsx์์ ์ฌ์ฉ์ ์๋์ฒ๋ผ ์ฌ์ฉํฉ๋๋ค.
When using it in app/ui/page.tsx, use it as shown below.
// compoents
import { Button } from './_components/button'
import { Dropdown } from './_components/dropdown';
export default function UIPage() {
return (
<main className="min-h-screen flex items-center justify-center bg-gray-50 p-4">
<div className="w-full max-w-sm bg-white rounded-2xl shadow-lg p-6 flex flex-col gap-6">
<h1 className="text-xl font-bold">๋ด UI ๋ผ์ด๋ธ๋ฌ๋ฆฌ / </h1>
<Dropdown />
<Button>์ ์ฅํ๊ธฐ/Save</Button>
</div>
</main>
)
}
๋งํ๋ณต์ 21์ฅ 22์ / Matthew 21: 22
“๋ํฌ๊ฐ ๊ธฐ๋ํ ๋์ ๋ฌด์์ด๋ ์ง ๋ฏฟ๊ณ ๊ตฌํ๋ ๊ฒ์ ๋ค ๋ฐ์ผ๋ฆฌ๋ผ ํ์๋๋ผ”
“And everything you ask in prayer, believing, you will receive.”