Next.js와 shadcn/ui에서 DropdownMenuTrigger의 asChild 속성에 대해 알아보기 🚀

엔케이·2025년 2월 21일
0
post-thumbnail

Next.js와 shadcn/ui에서 DropdownMenuTrigger의 asChild 속성에 대해 알아보기 🚀

안녕하세요! 이번 포스트에서는 Next.js에서 shadcn/ui 패키지의 DropdownMenuTrigger 컴포넌트를 사용할 때 등장하는 asChild 속성에 대해 살펴보려 합니다.
“이 속성은 언제 써야 하고, 왜 필요한 걸까?”라는 의문을 해결해봅시다! 🧐


asChild란? 🤔

Radix UI 기반의 DropdownMenuTrigger 컴포넌트(이를 확장한 shadcn/ui도 마찬가지)는 기본적으로 내부에서 <button> 태그를 만들어 제공합니다.
하지만 때로는 Link, div 혹은 CustomButton 같이 내가 원하는 컴포넌트를 그대로 트리거로 쓰고 싶을 때가 있죠.

그럴 때 asChild를 사용하면, 기본 <button> 래퍼를 생성하지 않고, 내가 전달한 컴포넌트 자체를 트리거로 사용하게 됩니다.

  • DOM 구조가 복잡하게 중첩되지 않아, 깔끔한 마크업을 유지할 수 있어요.
  • <button> 태그와 스타일이 충돌하거나, <Link>와 겹치는 문제도 해결할 수 있어요.

언제 / 왜 사용해야 할까? 🔍

  1. 특정 DOM 태그로 감싸지 않고 싶을 때

    기본 <button> 대신에 내가 전달한 컴포넌트가 직접 트리거가 되길 원할 때 사용합니다.

  2. 불필요한 DOM 계층을 제거하고 싶을 때

    <button> 태그가 추가로 생기는 걸 원치 않는다면 asChild로 중첩 구조를 없앨 수 있습니다.

  3. 스타일 겹침을 피하고 싶을 때

    button 태그 위에 또 버튼 스타일이 덧씌워지는 문제를 방지하고, 원하는 스타일링을 그대로 가져갈 수 있습니다.

  4. 하이드레이션(Hydration) 문제를 방지하고 싶을때

    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>

코드 예시 💻

아래 예시에서는 DropdownMenuTriggerasChild를 설정하여, 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 중첩 문제나 스타일 충돌 등을 말끔히 해결해주죠.

  • 핵심 포인트: “내가 직접 지정한 컴포넌트를 DOM에 그대로 렌더링하면서도, DropdownMenu 트리거 역할을 하게 만들고 싶을 때 asChild를 사용하라!”

참고 자료 📚

읽어주셔서 감사합니다! 더 궁금하신 점이 있으시면 언제든 댓글이나 문의 부탁드려요. 🙌

profile
FE 개발자

0개의 댓글