Post

Next.js에서 asChild 속성 사용하기

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를 함께 사용할 때 필수적으로 고려해야 할 패턴이므로, 프로젝트에서 적극 활용하면 좋다. 🚀

This post is licensed under CC BY 4.0 by the author.