Special Elements — svelte:로 시작하는 특수 요소들
svelte:window로 윈도우 이벤트를,svelte:head로 메타 태그를 — 컴포넌트 안에서 전역 요소를 다루는 Svelte만의 방법입니다.
개념 정의
Special Elements 는 svelte: 접두사로 시작하는 Svelte 전용 요소입니다. 일반 HTML로는 표현할 수 없는 동적 컴포넌트 렌더링, 윈도우/바디 이벤트 바인딩, HEAD 조작 등을 가능하게 합니다.
svelte:component — 동적 컴포넌트
<script>
import Home from './Home.svelte';
import About from './About.svelte';
import Contact from './Contact.svelte';
const routes = { home: Home, about: About, contact: Contact };
let currentRoute = $state('home');
</script>
<nav>
<button onclick={() => currentRoute = 'home'}>홈</button>
<button onclick={() => currentRoute = 'about'}>소개</button>
<button onclick={() => currentRoute = 'contact'}>연락</button>
</nav>
<!-- this에 컴포넌트를 동적으로 전달 -->
<svelte:component this={routes[currentRoute]} />
svelte:element — 동적 HTML 태그
<script>
let { level = 1, children } = $props();
// h1~h6 중 동적으로 선택
let tag = $derived(`h${Math.min(Math.max(level, 1), 6)}`);
</script>
<!-- 태그명을 동적으로 결정 -->
<svelte:element this={tag}>
{@render children()}
</svelte:element>
<!-- 사용 예시 -->
<Heading level={1}>제목 1</Heading>
<Heading level={2}>제목 2</Heading>
<Heading level={3}>제목 3</Heading>
svelte:window — 윈도우 이벤트
<script>
let innerWidth = $state(0);
let innerHeight = $state(0);
let scrollY = $state(0);
let online = $state(true);
function handleKeydown(e) {
if (e.key === 'Escape') {
console.log('ESC 키 눌림');
}
}
</script>
<!-- 윈도우 이벤트 리스너 (자동 정리됨) -->
<svelte:window
onkeydown={handleKeydown}
onscroll={() => {}}
bind:innerWidth
bind:innerHeight
bind:scrollY
bind:online
/>
<p>화면 크기: {innerWidth} x {innerHeight}</p>
<p>스크롤: {scrollY}px</p>
<p>네트워크: {online ? '온라인' : '오프라인'}</p>
<!-- 스크롤에 따른 헤더 숨기기 -->
<header class:hidden={scrollY > 100}>
네비게이션 바
</header>
<style>
header { position: fixed; top: 0; width: 100%; transition: transform 0.3s; }
.hidden { transform: translateY(-100%); }
</style>
svelte:document — 문서 이벤트
<script>
function handleVisibilityChange() {
if (document.hidden) {
console.log('탭 비활성화');
} else {
console.log('탭 활성화');
}
}
function handleSelectionChange() {
const selection = document.getSelection()?.toString();
if (selection) {
console.log('선택된 텍스트:', selection);
}
}
</script>
<svelte:document
onvisibilitychange={handleVisibilityChange}
onselectionchange={handleSelectionChange}
/>
svelte:body — 바디 이벤트
<script>
let isDragging = $state(false);
</script>
<svelte:body
ondragenter={() => isDragging = true}
ondragleave={() => isDragging = false}
ondrop={(e) => {
e.preventDefault();
isDragging = false;
console.log('파일 드롭됨');
}}
ondragover={(e) => e.preventDefault()}
/>
<div class:drag-active={isDragging}>
{isDragging ? '여기에 놓으세요!' : '파일을 드래그하세요'}
</div>
<style>
.drag-active { border: 2px dashed #ff3e00; background: #fff5f5; }
</style>
svelte:head — HEAD 태그 조작
<script>
let { title, description } = $props();
</script>
<svelte:head>
<title>{title} | 내 블로그</title>
<meta name="description" content={description} />
<meta property="og:title" content={title} />
<link rel="canonical" href="https://example.com" />
</svelte:head>
<h1>{title}</h1>
svelte:options — 컴파일러 옵션
<!-- 이 컴포넌트를 immutable로 처리 (최적화) -->
<svelte:options immutable />
<!-- 커스텀 엘리먼트로 컴파일 -->
<svelte:options customElement="my-component" />
svelte:boundary — 에러 바운더리 (Svelte 5)
<script>
import RiskyComponent from './RiskyComponent.svelte';
</script>
<svelte:boundary>
<RiskyComponent />
{#snippet failed(error, reset)}
<div class="error">
<p>오류 발생: {error.message}</p>
<button onclick={reset}>다시 시도</button>
</div>
{/snippet}
</svelte:boundary>
<style>
.error { background: #fee; padding: 1rem; border-radius: 4px; border: 1px solid #fcc; }
</style>
실전 예시 — 반응형 레이아웃
<script>
let innerWidth = $state(0);
let breakpoint = $derived(
innerWidth >= 1200 ? 'xl' :
innerWidth >= 992 ? 'lg' :
innerWidth >= 768 ? 'md' :
innerWidth >= 576 ? 'sm' : 'xs'
);
let isMobile = $derived(innerWidth < 768);
</script>
<svelte:window bind:innerWidth />
<div class="container breakpoint-{breakpoint}">
{#if isMobile}
<MobileNav />
{:else}
<DesktopNav />
{/if}
<main>
<p>현재 브레이크포인트: {breakpoint} ({innerWidth}px)</p>
</main>
</div>
면접 포인트
- "svelte:window가 addEventListener보다 나은 점은?": 컴포넌트가 소멸할 때 자동으로 이벤트 리스너가 제거됩니다. 수동으로 cleanup할 필요가 없어 메모리 누수 위험이 줄어듭니다.
- "svelte:boundary와 React ErrorBoundary의 차이는?": React ErrorBoundary는 클래스 컴포넌트에서만 사용 가능하고,
svelte:boundary는 마크업 어디서든 사용할 수 있으며 reset 기능도 기본 제공됩니다.
정리
Special Elements는 Svelte가 HTML의 한계를 확장하는 방법입니다. 컴포넌트 안에서 window, document, head를 안전하게 다루고, 동적 컴포넌트와 에러 바운더리까지 — 이 도구들을 알면 Svelte의 활용 범위가 크게 넓어집니다.
댓글 로딩 중...