React의 children prop처럼, Svelte에서도 컴포넌트 안에 컨텐츠를 끼워 넣을 수 있습니다 — Svelte 5에서는 Snippet이 그 역할을 합니다.

개념 정의

슬롯(Slot) 은 부모 컴포넌트가 자식 컴포넌트의 마크업 일부를 주입할 수 있게 하는 패턴입니다. Svelte 5에서는 전통적인 <slot> 대신 Snippet 과 children prop을 권장합니다.

children — 기본 컨텐츠 주입

SVELTE
<!-- Card.svelte -->
<script>
  let { children, title } = $props();
</script>

<div class="card">
  <h2>{title}</h2>
  <div class="card-body">
    {@render children()}
  </div>
</div>

<style>
  .card { border: 1px solid #ddd; border-radius: 8px; padding: 1rem; }
  .card-body { margin-top: 0.5rem; }
</style>
SVELTE
<!-- App.svelte -->
<script>
  import Card from './Card.svelte';
</script>

<Card title="공지사항">
  <p>이 내용이 card-body 안에 렌더링됩니다.</p>
  <button>확인</button>
</Card>

{@render children()}은 부모가 전달한 컨텐츠를 렌더링합니다.

기본 컨텐츠 (Fallback)

SVELTE
<!-- Alert.svelte -->
<script>
  let { children, type = 'info' } = $props();
</script>

<div class="alert alert-{type}">
  {#if children}
    {@render children()}
  {:else}
    <p>기본 알림 메시지입니다.</p>
  {/if}
</div>
SVELTE
<!-- children을 전달하지 않으면 기본 컨텐츠 표시 -->
<Alert type="warning" />

<!-- children을 전달하면 커스텀 컨텐츠 표시 -->
<Alert type="error">
  <strong>오류 발생!</strong> 잠시 후 다시 시도해주세요.
</Alert>

Named Snippet — 여러 영역 주입

SVELTE
<!-- Layout.svelte -->
<script>
  let { header, children, footer } = $props();
</script>

<div class="layout">
  <header>
    {#if header}
      {@render header()}
    {/if}
  </header>

  <main>
    {@render children()}
  </main>

  <footer>
    {#if footer}
      {@render footer()}
    {:else}
      <p>기본 푸터</p>
    {/if}
  </footer>
</div>
SVELTE
<!-- App.svelte -->
<script>
  import Layout from './Layout.svelte';
</script>

<Layout>
  {#snippet header()}
    <nav>내비게이션 바</nav>
  {/snippet}

  <p>메인 컨텐츠가 여기에 들어갑니다.</p>

  {#snippet footer()}
    <p>커스텀 푸터 2026</p>
  {/snippet}
</Layout>

Snippet에 데이터 전달

SVELTE
<!-- List.svelte -->
<script>
  let { items, renderItem, children } = $props();
</script>

<ul>
  {#each items as item, index}
    <li>
      {#if renderItem}
        {@render renderItem(item, index)}
      {:else}
        {item}
      {/if}
    </li>
  {/each}
</ul>
SVELTE
<!-- App.svelte -->
<script>
  import List from './List.svelte';

  const users = [
    { name: '홍길동', role: 'admin' },
    { name: '김철수', role: 'user' },
  ];
</script>

<List items={users}>
  {#snippet renderItem(user, index)}
    <strong>{index + 1}. {user.name}</strong>
    <span class="badge">{user.role}</span>
  {/snippet}
</List>

이 패턴은 React의 Render Props 패턴과 동일한 역할을 합니다.

실전 예시 — Modal 컴포넌트

SVELTE
<!-- Modal.svelte -->
<script>
  let { open = $bindable(false), title, children, actions } = $props();

  function close() {
    open = false;
  }
</script>

{#if open}
  <div class="backdrop" onclick={close}>
    <div class="modal" onclick={(e) => e.stopPropagation()}>
      <div class="modal-header">
        <h2>{title}</h2>
        <button onclick={close}>X</button>
      </div>
      <div class="modal-body">
        {@render children()}
      </div>
      {#if actions}
        <div class="modal-actions">
          {@render actions()}
        </div>
      {/if}
    </div>
  </div>
{/if}

<style>
  .backdrop { position: fixed; inset: 0; background: rgba(0,0,0,0.5); display: grid; place-items: center; }
  .modal { background: white; border-radius: 8px; padding: 1.5rem; min-width: 400px; }
</style>
SVELTE
<!-- App.svelte -->
<script>
  import Modal from './Modal.svelte';
  let showModal = $state(false);
</script>

<button onclick={() => showModal = true}>모달 열기</button>

<Modal bind:open={showModal} title="확인">
  <p>정말 삭제하시겠습니까?</p>

  {#snippet actions()}
    <button onclick={() => showModal = false}>취소</button>
    <button onclick={() => { /* 삭제 로직 */ showModal = false; }}>삭제</button>
  {/snippet}
</Modal>

면접 포인트

  • "Svelte 5에서 slot이 Snippet으로 바뀐 이유는?": <slot>은 Web Components의 slot과 혼동될 수 있고, 데이터 전달 방식이 let: 디렉티브로 제한적이었습니다. Snippet은 일반 함수처럼 매개변수를 받을 수 있어 더 유연합니다.
  • "React children과 Svelte children의 차이는?": React의 children은 ReactNode 타입의 prop이고, Svelte의 children은 {@render}로 호출하는 Snippet입니다. Svelte 방식이 조건부 렌더링과 데이터 전달에서 더 명시적입니다.

정리

Snippet은 Svelte 5에서 컴포넌트 합성의 핵심 패턴입니다. children으로 기본 컨텐츠를, named snippet으로 여러 영역을, 매개변수로 데이터 전달까지 — 이 세 가지만 알면 재사용 가능한 컴포넌트를 자유자재로 만들 수 있습니다.

댓글 로딩 중...