Svelte Compiler
The Svelte compiler reads visual.components from a xtyle definition and generates Svelte 5 component files. Each component gets typed props, size and variant support, state handling, and Snippet-based content slots.
Installation
Section titled “Installation”npm install @xtylejs/compiler-svelteCLI Usage
Section titled “CLI Usage”xtyle compile brand.xtyle.json --target svelteGenerated components are written to ./out/svelte/. Each component gets its own file named in PascalCase (e.g. Button.svelte, Panel.svelte, Input.svelte).
Programmatic Usage
Section titled “Programmatic Usage”import { compile } from "@xtylejs/compiler-svelte";
const components = compile(definition);
for (const [filename, source] of Object.entries(components)) { console.log(`${filename}:\n${source}`);}The compile function returns a Record<string, string> mapping filenames to Svelte component source code.
Generated Component Features
Section titled “Generated Component Features”HTML Element Mapping
Section titled “HTML Element Mapping”The compiler infers the HTML element from the component name:
| Component Name | HTML Element |
|---|---|
button | <button> |
input | <input> |
select | <select> |
textarea | <textarea> |
a | <a> |
| anything else | <div> |
Typed Props
Section titled “Typed Props”Every generated component uses a TypeScript Props interface with $props():
<script lang="ts"> import type { Snippet } from 'svelte';
interface Props { size?: 'sm' | 'md' | 'lg'; variant?: 'secondary'; disabled?: boolean; onclick?: (e: MouseEvent) => void; children?: Snippet; }
let { size, variant, disabled = false, onclick, children }: Props = $props();</script>Size and Variant Props
Section titled “Size and Variant Props”When a component defines sizes or variants, the generated component accepts size and variant props as union types. These map to BEM-style modifier classes:
<button class="xtyle-button{size ? ` xtyle-button--${size}` : ''}{variant ? ` xtyle-button--${variant}` : ''}" class:xtyle-button--disabled={disabled} {disabled} {onclick}>Content Slots
Section titled “Content Slots”Button components use children via Svelte 5 Snippets. Div-based components with multiple anatomy parts use named Snippets for each part:
<div class="xtyle-panel"> {#if header} <div class="xtyle-panel-header"> {@render header()} </div> {/if} <div class="xtyle-panel-body"> {@render children?.()} </div></div>Input Binding
Section titled “Input Binding”Input components use bind:value with $bindable() for two-way binding:
<script lang="ts"> interface Props { size?: 'sm' | 'md' | 'lg'; disabled?: boolean; value?: string; placeholder?: string; oninput?: (e: Event) => void; }
let { size, disabled = false, value = $bindable(''), placeholder = '', oninput }: Props = $props();</script>
<input class="xtyle-input{size ? ` xtyle-input--${size}` : ''}" class:xtyle-input--disabled={disabled} {disabled} bind:value {placeholder} {oninput}/>Example
Section titled “Example”Given the Midnight Diner button definition, the compiler generates Button.svelte:
<script lang="ts"> import type { Snippet } from 'svelte';
interface Props { size?: 'sm' | 'md' | 'lg'; variant?: 'secondary'; disabled?: boolean; onclick?: (e: MouseEvent) => void; children?: Snippet; }
let { size, variant, disabled = false, onclick, children }: Props = $props();</script>
<button class="xtyle-button{size ? ` xtyle-button--${size}` : ''}{variant ? ` xtyle-button--${variant}` : ''}" class:xtyle-button--disabled={disabled} {disabled} {onclick}> <span class="xtyle-button-label"> {@render children?.()} </span></button>The generated components use CSS classes matching the CSS compiler’s output. Pair both compilers to get styled, functional components from a single definition.
Pairing with CSS
Section titled “Pairing with CSS”The Svelte components reference class names that the CSS compiler generates. Compile both targets together for a complete result:
xtyle compile brand.xtyle.json --target css svelteImport the CSS file in your Svelte app and the generated components pick up their styles automatically.