Next.js에서 asChild 속성 사용하기
asChild Prop의 사용 이유와 활용 방법
asChild
prop은 Radix UI에서 제공하는 기능으로, 기본적으로 특정 컴포넌트의 기본 HTML 요소를 자식 요소로 대체할 때 사용된다. 이를 통해 불필요한 DOM 중첩을 방지하고, 스타일과 기능을 유지하면서 더 유연한 컴포넌트 활용이 가능해진다.
1. asChild의 기본 개념
일반적으로 UI 라이브러리에서 제공하는 버튼(Button), 링크(Link) 같은 컴포넌트는 특정 HTML 요소(<button>
, <a>
등)로 렌더링된다. 하지만 Next.js의 <Link>
와 함께 사용할 경우, <button>
안에 <a>
가 중첩되는 HTML 유효성 문제(Invalid DOM nesting)가 발생할 수 있다.
🚨 문제점: 중첩된 HTML 태그
1
2
3
4
5
6
import Link from "next/link";
import { Button } from "@/components/ui/button";
<Button>
<Link href="/dashboard">Go to Dashboard</Link>
</Button>;
⚠️ 위 코드의 문제점:
<button>
내부에<a>
태그가 중첩되어 HTML 유효성 검사에서 오류 발생- 브라우저에서 올바르게 동작하지 않을 가능성이 있음
✅ 해결 방법: asChild 사용
1
2
3
<Button asChild>
<Link href="/dashboard">Go to Dashboard</Link>
</Button>
💡 asChild
를 사용하면:
<Button>
의 기본<button>
태그가<Link>
로 대체됨<Button>
의 스타일과 속성이<Link>
에 적용됨- HTML 유효성 문제가 해결됨
2. asChild 사용의 장점
✅ 1. HTML 구조 유지 (시맨틱 구조)
<button>
내부에 <a>
가 중첩되는 비정상적인 HTML 구조를 방지하여, 시맨틱 HTML을 유지할 수 있다.
✅ 2. 접근성(Accessibility) 향상
asChild
를 사용하면 <button>
의 스타일과 기능이 다른 요소로 전달되므로, 접근성(ARIA 속성, 키보드 네비게이션)이 유지된다.
✅ 3. 불필요한 DOM 중첩 방지
1
2
3
<Button>
<Link href="/about">About</Link>
</Button>
🚨 위 코드는 <button>
안에 <a>
가 중첩되므로 잘못된 마크업이다.
✅ asChild
를 사용하면 <Button>
자체가 <Link>
로 변경되므로 문제 해결 가능.
✅ 4. 스타일과 기능을 다른 요소에 적용 가능
컴포넌트의 스타일과 동작을 유지하면서, 특정 상황에 맞게 다른 태그(div
, span
, a
등)로 쉽게 변경할 수 있다.
3. 실전 예제: Next.js Link와 함께 사용
❌ 일반적인 문제 코드
1
2
3
<Button>
<Link href="/profile">Go to Profile</Link>
</Button>
<button>
내부에<a>
가 중첩됨 → HTML 구조 오류
✅ asChild를 사용한 올바른 코드
1
2
3
<Button asChild>
<Link href="/profile">Go to Profile</Link>
</Button>
<Button>
이<Link>
로 대체되므로, 올바른 HTML 구조 유지<Button>
의 스타일과 기능을<Link>
가 그대로 사용 가능
4. 다양한 사용 사례
1️⃣ asChild
로 다른 태그 적용하기
1
2
3
<Button asChild>
<span>Click me</span>
</Button>
<Button>
이<span>
으로 대체됨 →<span>
요소가 버튼처럼 동작- 스타일과 클릭 이벤트는 그대로 유지됨
2️⃣ Next.js의 Link
와 함께 사용
1
2
3
<Button asChild>
<Link href="/dashboard">Dashboard</Link>
</Button>
<button>
대신<a>
태그로 렌더링되어 SEO와 접근성 유지- 스타일과 인터랙션 기능은 그대로 적용
3️⃣ div
로 변경하여 특정 UI 구현
1
2
3
4
5
<Button asChild>
<div role="button" tabIndex={0}>
Custom Div Button
</div>
</Button>
<Button>
을<div>
로 변경하여, 특정 UI 요구사항에 맞게 활용 가능role="button"
과tabIndex={0}
을 추가해 접근성을 유지
5. 결론
asChild
prop을 사용하면: ✅ 시맨틱 HTML을 유지하여 잘못된 태그 중첩을 방지할 수 있다.
✅ 스타일과 기능을 유지하면서도 다양한 태그로 변경할 수 있다.
✅ Next.js의 <Link>
와 같은 컴포넌트와 함께 사용할 때 유용하다.
특히 Radix UI와 Next.js를 함께 사용할 때 필수적으로 고려해야 할 패턴이므로, 프로젝트에서 적극 활용하면 좋다. 🚀