[JavaScript][Vue.js] Slot 정리 - 부모가 자식 컴포넌트에 UI를 주입하는 방법

2026. 8. 26. 13:27·개발/JavaScript
반응형

Vue에서 컴포넌트를 만들다 보면 겉모양은 같지만 내부 내용만 바뀌는 UI를 만들고 싶은 경우가 있다.

예를 들어 다음과 같은 카드 컴포넌트를 생각해보자.

┌──────────────────────┐
│                      │
│        내용           │
│                      │
└──────────────────────┘

카드의 외곽 디자인은 같지만 내부에는 상황에 따라 서로 다른 내용을 넣고 싶을 수 있다.

카드 1
→ 날씨 정보

카드 2
→ 사용자 정보

카드 3
→ 공지사항

이럴 때 사용하는 것이 Slot이다.

Slot은 쉽게 말하면,

자식 컴포넌트가 미리 비워둔 영역에 부모 컴포넌트가 원하는 HTML이나 컴포넌트를 넣을 수 있게 하는 기능이다.


Slot의 기본 구조

먼저 자식 컴포넌트에서 <slot>을 선언한다.

<!-- BaseCard.vue -->
<template>
  <div class="card">
    <slot></slot>
  </div>
</template>

여기서

<slot></slot>

부분이 부모가 내용을 넣을 자리다.

부모 컴포넌트에서는 다음과 같이 사용할 수 있다.

<BaseCard>
  <h2>공지사항</h2>
  <p>새로운 공지가 있습니다.</p>
</BaseCard>

그러면 부모가 작성한 내용이 자식 컴포넌트의 <slot> 위치에 들어간다.

개념적으로는 다음과 같이 렌더링된다.

<div class="card">
  <h2>공지사항</h2>
  <p>새로운 공지가 있습니다.</p>
</div>

전체 흐름은 다음과 같다.

Parent Component

<BaseCard>
  <h2>공지사항</h2>
</BaseCard>

        ↓

Child Component

<div class="card">
  <slot />
</div>

        ↓

실제 화면

<div class="card">
  <h2>공지사항</h2>
</div>

Slot과 Props의 차이

Props와 Slot은 둘 다 부모에서 자식으로 무언가를 전달한다는 점에서는 비슷하다.

하지만 전달하는 대상이 다르다.

Props는 데이터를 전달한다.

<WeatherCard
  :city-name="cityName"
  :temperature="25"
/>

여기서 전달하는 것은 다음과 같은 값이다.

"서울"
25
true
객체
배열

반면 Slot은 HTML 구조나 UI 자체를 전달한다.

<BaseCard>
  <h2>서울 날씨</h2>
  <p>현재 기온 25도</p>
  <button>상세보기</button>
</BaseCard>

즉 차이를 정리하면 다음과 같다.

Props
→ 데이터 전달

Slot
→ HTML / UI 전달

왜 Slot을 사용할까?

Slot의 가장 큰 장점은 레이아웃을 재사용할 수 있다는 점이다.

예를 들어 카드 디자인이 다음과 같이 동일하다고 해보자.

<template>
  <div class="card">
    ...
  </div>
</template>

카드마다 내용을 직접 작성하면 비슷한 구조를 계속 반복해야 한다.

하지만 Slot을 사용하면 카드의 공통 디자인은 하나만 만들고 내부 내용만 바꿀 수 있다.

<BaseCard>
  <h2>사용자 정보</h2>
  <p>홍길동</p>
</BaseCard>
<BaseCard>
  <h2>날씨 정보</h2>
  <p>서울 25도</p>
</BaseCard>
<BaseCard>
  <h2>공지사항</h2>
  <p>서버 점검 안내</p>
</BaseCard>

같은 BaseCard를 계속 재사용하면서 내용만 바꾸는 것이다.


기본 Slot

가장 기본적인 Slot은 이름이 없는 Slot이다.

자식:

<!-- BaseCard.vue -->
<template>
  <div class="card">
    <slot></slot>
  </div>
</template>

부모:

<BaseCard>
  <h2>Vue Slot</h2>
  <p>Slot 기본 예제입니다.</p>
</BaseCard>

부모가 전달한 모든 내용이 자식의 <slot> 위치에 삽입된다.


Slot의 기본값

부모가 아무 내용도 전달하지 않는 경우를 대비해 기본 내용을 지정할 수도 있다.

<template>
  <div class="card">
    <slot>
      <p>기본 콘텐츠입니다.</p>
    </slot>
  </div>
</template>

부모가 다음처럼 사용하면

<BaseCard />

화면에는

기본 콘텐츠입니다.

가 표시된다.

반대로 부모가 내용을 전달하면

<BaseCard>
  <h2>새로운 내용</h2>
</BaseCard>

기본값 대신 부모가 전달한 내용이 표시된다.

부모 콘텐츠 있음
→ 부모 콘텐츠 사용

부모 콘텐츠 없음
→ slot 기본값 사용

Named Slot

하나의 컴포넌트에 여러 개의 내용을 각각 다른 위치에 넣고 싶다면 Named Slot을 사용할 수 있다.

예를 들어 카드가 다음 구조라고 해보자.

┌──────────────────────┐
│ Header               │
├──────────────────────┤
│ Main Content         │
├──────────────────────┤
│ Footer               │
└──────────────────────┘

자식 컴포넌트에서 각 Slot에 이름을 지정한다.

<template>
  <div class="card">

    <header>
      <slot name="header"></slot>
    </header>

    <main>
      <slot></slot>
    </main>

    <footer>
      <slot name="footer"></slot>
    </footer>

  </div>
</template>

부모에서는 각 이름에 맞는 내용을 전달한다.

<BaseCard>

  <template #header>
    <h2>게시글 제목</h2>
  </template>

  <p>게시글 내용입니다.</p>

  <template #footer>
    <button>확인</button>
  </template>

</BaseCard>

여기서

#header

는

v-slot:header

의 축약형이다.

마찬가지로

#footer

는

v-slot:footer

를 줄여 쓴 것이다.

정리하면 다음과 같다.

#header
→ header slot

#footer
→ footer slot

이름이 없는 영역
→ 기본 slot

Scoped Slot

일반 Slot은 부모가 자식에게 UI를 전달하는 구조다.

Parent
   ↓
HTML / UI
   ↓
Child

Scoped Slot은 여기서 조금 더 나아가 자식 컴포넌트가 가진 데이터를 부모가 받아서 화면을 구성할 수 있게 한다.

예를 들어 자식이 사용자 데이터를 가지고 있다고 해보자.

<script setup>
const userName = '홍길동'
</script>

<template>
  <slot :name="userName"></slot>
</template>

자식은 Slot을 통해 userName을 전달한다.

부모에서는 이를 받을 수 있다.

<ChildComponent v-slot="slotData">
  <p>사용자 이름: {{ slotData.name }}</p>
</ChildComponent>

흐름은 다음과 같다.

Child Component

userName = "홍길동"

      ↓

slot에 데이터 전달

      ↓

Parent Component

slotData.name

      ↓

홍길동 출력

즉 Scoped Slot은 자식이 데이터를 제공하고, 부모가 그 데이터를 이용해 어떤 HTML을 그릴지 결정하는 방식이다.


Props, Emits, Slot 비교

Vue 컴포넌트 간 통신을 정리하면 다음과 같이 구분할 수 있다.

Props

Parent
   ↓
Child

데이터 전달
Emits

Child
   ↓
Parent

이벤트 전달
Slot

Parent
   ↓
Child의 빈 영역

HTML / UI 전달
Scoped Slot

Child
   ↓
Parent

Slot용 데이터 전달

간단히 비교하면 다음과 같다.

기능 방향 전달하는 것
Props 부모 → 자식 데이터
Emits 자식 → 부모 이벤트, Payload
Slot 부모 → 자식 HTML, UI
Scoped Slot 자식 → 부모 Slot에서 사용할 데이터

어떤 상황에서 Slot을 사용할까?

Slot은 외곽 구조는 같고 내부 내용만 달라지는 컴포넌트에 적합하다.

대표적으로 다음과 같은 UI가 있다.

Card
Modal
Dialog
Layout
Panel
Popup
Form Wrapper

예를 들어 Modal 컴포넌트를 만들 수 있다.

<template>
  <div class="modal">
    <div class="modal-content">
      <slot></slot>
    </div>
  </div>
</template>

사용할 때는 내용만 바꾼다.

<BaseModal>
  <h2>삭제 확인</h2>
  <p>정말 삭제하시겠습니까?</p>
</BaseModal>

또 다른 곳에서는

<BaseModal>
  <h2>로그인</h2>
  <LoginForm />
</BaseModal>

처럼 같은 Modal 디자인을 재사용할 수 있다.

즉 Slot을 이용하면 컴포넌트가 특정 내용에 종속되지 않고 훨씬 유연해진다.


Props와 Slot을 같이 사용할 수도 있다

Props와 Slot은 서로 대체하는 관계가 아니다.

하나의 컴포넌트에서 동시에 사용할 수도 있다.

예를 들어 카드의 상태는 Props로 받고, 카드 내부 내용은 Slot으로 받을 수 있다.

<!-- BaseCard.vue -->

<script setup>
defineProps({
  title: String
})
</script>

<template>
  <div class="card">
    <h2>{{ title }}</h2>

    <slot></slot>
  </div>
</template>

부모:

<BaseCard title="사용자 정보">
  <p>이름: 홍길동</p>
  <button>수정</button>
</BaseCard>

구조를 보면 다음과 같다.

title
→ Props

<p>, <button>
→ Slot

이런 방식으로 데이터와 UI를 각각 적절한 방식으로 전달할 수 있다.


전체 구조 정리

Slot의 기본적인 구조를 하나로 정리하면 다음과 같다.

        Parent Component

        <BaseCard>
          원하는 HTML
        </BaseCard>

               │
               │ UI 전달
               ▼

         Child Component

       ┌─────────────────┐
       │                 │
       │     <slot>      │
       │                 │
       └─────────────────┘

               ↓

         실제 화면 출력

Named Slot을 사용하면 여러 위치를 나눌 수도 있다.

          Parent

   #header   기본   #footer
       │      │       │
       ▼      ▼       ▼

┌─────────────────────────┐
│       header slot       │
├─────────────────────────┤
│       default slot      │
├─────────────────────────┤
│       footer slot       │
└─────────────────────────┘

정리

Slot은 자식 컴포넌트 내부에 부모가 원하는 HTML이나 UI를 넣을 수 있게 하는 기능이다.

가장 기본적인 형태는 다음과 같다.

<slot></slot>

부모에서는

<BaseCard>
  <h2>내용</h2>
</BaseCard>

처럼 사용한다.

기능별로 보면 다음과 같다.

Default Slot
→ 하나의 기본 영역에 콘텐츠 삽입

Named Slot
→ 여러 위치를 이름으로 구분

Scoped Slot
→ 자식의 데이터를 부모가 받아 UI 구성

Props와 비교하면 차이는 더욱 명확하다.

Props
→ 데이터를 전달

Slot
→ HTML / UI를 전달

따라서 한 문장으로 정리하면 다음과 같다.

Slot은 재사용 가능한 컴포넌트의 특정 영역을 비워두고, 부모 컴포넌트가 그 영역에 원하는 HTML이나 컴포넌트를 주입할 수 있게 하는 Vue의 UI 조합 기능이다.

반응형

'개발 > JavaScript' 카테고리의 다른 글

[JavaScript][Vue.js] Pinia와 Store 정리 - 전역 상태 관리 이해하기  (0) 2026.08.26
[JavaScript][Vue.js] provide / inject 정리 - 깊은 컴포넌트 간 데이터 전달  (0) 2026.08.26
[JavaScript][Vue.js] Props와 Emits 정리 - 부모·자식 컴포넌트 통신  (0) 2026.08.26
[JavaScript][Vue.js] Component Lifecycle과 Lifecycle Hook 정리  (0) 2026.08.26
[JavaScript][Vue.js] Composition API란? - Options API와의 차이부터 ref, computed, watch까지  (0) 2026.08.26
'개발/JavaScript' 카테고리의 다른 글
  • [JavaScript][Vue.js] Pinia와 Store 정리 - 전역 상태 관리 이해하기
  • [JavaScript][Vue.js] provide / inject 정리 - 깊은 컴포넌트 간 데이터 전달
  • [JavaScript][Vue.js] Props와 Emits 정리 - 부모·자식 컴포넌트 통신
  • [JavaScript][Vue.js] Component Lifecycle과 Lifecycle Hook 정리
danieLee
danieLee
개발일지
  • danieLee
    Code log
    danieLee
  • 전체
    오늘
    어제
    • 분류 전체보기 (77)
      • 개발 (76)
        • C++ (3)
        • java (6)
        • JavaScript (9)
        • python (0)
        • AWS (2)
        • Docker (6)
        • git (0)
        • 백엔드 (4)
        • Spring (7)
        • Django (2)
        • AI (3)
        • 코테 준비 (13)
        • 알고리즘 (6)
        • SKALA 4기 (13)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    대학생
    프론트
    Ai
    개념
    API
    코테
    개발
    JavaScript
    파이썬
    서버
    알고리즘
    프로그래머스
    js
    백엔드
    spring
    4기
    java
    개발자
    vue.js
    skala
  • 최근 댓글

  • 최근 글

  • 반응형
  • hELLO· Designed By정상우.v4.10.1
danieLee
[JavaScript][Vue.js] Slot 정리 - 부모가 자식 컴포넌트에 UI를 주입하는 방법
상단으로

티스토리툴바