
안녕하세요! 이번 포스트에서는 Next.js에서 shadcn/ui 패키지의 DropdownMenuTrigger 컴포넌트를 사용할 때 등장하는 asChild 속성에 대해 살펴보려 합니다.
“이 속성은 언제 써야 하고, 왜 필요한 걸까?”라는 의문을 해결해봅시다! 🧐
Radix UI 기반의 DropdownMenuTrigger 컴포넌트(이를 확장한 shadcn/ui도 마찬가지)는 기본적으로 내부에서 <button> 태그를 만들어 제공합니다.
하지만 때로는 Link, div 혹은 CustomButton 같이 내가 원하는 컴포넌트를 그대로 트리거로 쓰고 싶을 때가 있죠.
그럴 때 asChild를 사용하면, 기본 <button> 래퍼를 생성하지 않고, 내가 전달한 컴포넌트 자체를 트리거로 사용하게 됩니다.
<button> 태그와 스타일이 충돌하거나, <Link>와 겹치는 문제도 해결할 수 있어요.기본 <button> 대신에 내가 전달한 컴포넌트가 직접 트리거가 되길 원할 때 사용합니다.
<button> 태그가 추가로 생기는 걸 원치 않는다면 asChild로 중첩 구조를 없앨 수 있습니다.
button 태그 위에 또 버튼 스타일이 덧씌워지는 문제를 방지하고, 원하는 스타일링을 그대로 가져갈 수 있습니다.
nextjs에서는 <button>태그안에 <button>을 추가하면 하이드레이션 문제가 발생합니다. 이는 인터랙티브 컨텐츠를 겹쳐서 사용하면 안되는 문제 때문입니다.
Interactive Content cannot be nested (
<a>nested in a<a>tag,<button>nested in a<button>tag, etc.)
asChild를 안 썼을 때, html tag 구성
<button>
<button>
...
</button>
</button>
asChild를 썼을 때, html tag 구성
<button>
...
</button>
아래 예시에서는 DropdownMenuTrigger에 asChild를 설정하여, Link 태그를 그대로 트리거로 사용하고 있습니다.
import Link from 'next/link'
import {
DropdownMenu,
DropdownMenuTrigger,
DropdownMenuContent,
DropdownMenuItem,
} from "@/components/ui/dropdown-menu"
export default function Demo() {
return (
<DropdownMenu>
{/* asChild로 Link 자체를 트리거로 사용합니다. */}
<DropdownMenuTrigger asChild>
<Link href="/">
홈으로
</Link>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem>메뉴 1</DropdownMenuItem>
<DropdownMenuItem>메뉴 2</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
)
}
asChild 옵션을 제거한다면, Link 바깥에 <button>이 다시 생기면서 중복 DOM 구조가 형성될 것입니다.asChild는 작지만 꽤나 유용한 속성입니다.
props를 “넘겨서 끝내는” 것만으로는 해결되지 않는, DOM 중첩 문제나 스타일 충돌 등을 말끔히 해결해주죠.
asChild를 사용하라!”읽어주셔서 감사합니다! 더 궁금하신 점이 있으시면 언제든 댓글이나 문의 부탁드려요. 🙌