Безстилевые компоненты представляют собой элементы интерфейса, которые предоставляют функциональность без привязки к конкретной визуальной стилистике. В SvelteKit это особенно полезно для построения гибких UI-библиотек, где дизайн задаётся внешними CSS-фреймворками или Tailwind, а компоненты остаются полностью универсальными.
Важные преимущества безстилевых компонентов:
Типичный безстилевой компонент в SvelteKit состоит из трёх частей:
script блок, где определяются
переменные, события и функции.markup, описывающая
структуру HTML.Пример простого безстилевого компонента кнопки:
<script lang="ts">
export let type: 'button' | 'submit' | 'reset' = 'button';
export let disabled: boolean = false;
export let onClick: () => void;
</script>
<button type={type} disabled={disabled} on:click={onClick}>
<slot>Кнопка</slot>
</button>
Ключевые моменты:
Безстилевые компоненты часто используют prop
class для передачи кастомных стилей.
Пример использования кнопки:
<MyButton class="bg-blue-500 text-white px-4 py-2 rounded" onCl ick={handleClick}>
Отправить
</MyButton>
Такой подход позволяет полностью отделить визуальную часть от логики, сохраняя компонент универсальным.
Дополнительно можно использовать композицию классов через
utility-библиотеки (например, clsx или
classnames):
<script lang="ts">
import clsx from 'clsx';
export let primary: boolean = false;
export let className: string = '';
</script>
<button class={clsx('px-4 py-2 rounded', primary && 'bg-blue-500 text-white', className)}>
<slot></slot>
</button>
Слоты — основной инструмент безстилевых компонентов для поддержки вложенного контента.
Пример компонента карточки:
<div class="border rounded p-4 shadow">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
Использование:
<Card>
<h2 slot="header">Заголовок</h2>
<p>Основной контент карточки.</p>
<button slot="footer" class="btn-primary">Действие</button>
</Card>
Слоты позволяют:
Безстилевые компоненты часто работают с внутренним состоянием, но не навязывают его визуализацию. Например, компонент раскрывающегося меню:
<script lang="ts">
import { writable } from 'svelte/store';
const open = writable(false);
function toggle() {
open.update(value => !value);
}
</script>
<div>
<button on:click={toggle}>
<slot name="trigger">Открыть меню</slot>
</button>
{#if $open}
<div>
<slot name="content">Содержимое меню</slot>
</div>
{/if}
</div>
Особенности:
Безстилевые компоненты требуют особого внимания к доступности. Основные рекомендации:
role, aria-expanded,
aria-controls).tabindex
и обработчики on:keydown.Пример accessible переключателя:
<script lang="ts">
export let checked: boolean = false;
export let onChange: (value: boolean) => void;
</script>
<div role="switch" aria-checked={checked} tabindex="0"
on:click={() => onChange(!checked)}
on:keydown={(e) => e.key === 'Enter' && onChange(!checked)}>
<slot>{checked ? 'Включено' : 'Выключено'}</slot>
</div>
Безстилевые компоненты идеально сочетаются с утилитарными CSS-фреймворками.
Пример: кнопка с Tailwind и вариациями:
<script lang="ts">
export let variant: 'primary' | 'secondary' = 'primary';
export let className: string = '';
</script>
<button class={`px-4 py-2 rounded ${variant === 'primary' ? 'bg-blue-500 text-white' : 'bg-gray-200 text-black'} ${className}`}>
<slot></slot>
</button>
Это обеспечивает:
Ключевые принципы создания безстилевых компонентов:
class или utility-функции.Такая архитектура обеспечивает максимальную переиспользуемость, гибкость и чистоту кода, что критично для крупных SvelteKit UI-библиотек.