No Login Data Private Local Save

Svelte Component Boilerplate - Online Quick .svelte Template

7
0
0
0
Configuration

.svelte
Use PascalCase (e.g., UserCard)


Svelte 4 JavaScript CSS
MyComponent.svelte
Frequently Asked Questions

A Svelte component boilerplate is a pre-structured .svelte file template that includes the essential sections: <script> for logic, HTML template for markup, and <style> for scoped CSS. It saves developers time by providing a consistent starting point for building Svelte components, eliminating repetitive setup code. Svelte's single-file component architecture keeps everything co-located, making components easy to understand and maintain.

Svelte 5 introduced runes — a new reactivity system using $state(), $derived(), $effect(), and $props(). These replace the traditional export let props and $: reactive declarations found in Svelte 4. Runes offer more explicit reactivity, better TypeScript inference, and work consistently across .svelte, .js, and .ts files. Svelte 4 remains widely used and stable, while Svelte 5 represents the future direction of the framework. Both are fully supported in this generator.

To use TypeScript in a Svelte component, add lang="ts" to the script tag: <script lang="ts">. In Svelte 4, you can type props directly: export let name: string = 'World';. In Svelte 5 with runes, use $props() with an interface: let { name = 'World' }: Props = $props();. Ensure your build tool (Vite, SvelteKit, Rollup) has TypeScript support configured via svelte-preprocess or vite-plugin-svelte.

Yes! By default, all CSS inside a Svelte <style> block is scoped to that component only. Svelte achieves this by adding unique class hashes to elements during compilation. This prevents style leakage across components without needing CSS Modules or BEM naming conventions. If you need global styles, use :global(.selector) inside your style block. Svelte also supports lang="scss", lang="less", and PostCSS for preprocessing — just install the corresponding preprocessor package.

Svelte provides lifecycle functions: onMount (runs after component renders — great for API calls), onDestroy (cleanup before removal), beforeUpdate (runs before DOM updates), and afterUpdate (runs after DOM syncs). In Svelte 5, these are largely replaced by $effect() which automatically handles setup and cleanup. Use onMount for fetching data, setting up subscriptions, or initializing third-party libraries. Always return a cleanup function from onMount to prevent memory leaks.

In Svelte 4, use createEventDispatcher from 'svelte' to dispatch custom events: dispatch('update', { data }). Parent components listen with on:update={handler}. In Svelte 5, the recommended pattern uses callback props: declare let { onupdate } = $props(); and call onupdate(data) directly. This aligns Svelte with standard JavaScript patterns and improves TypeScript support. Both approaches work in Svelte 5 for backward compatibility.

Absolutely! The generated .svelte components work seamlessly in SvelteKit projects. Simply place the downloaded file in your src/lib/components/ directory and import it where needed. SvelteKit adds file-based routing, server-side rendering, and API endpoints on top of Svelte components — but the component syntax remains identical. Whether you're building a standalone Svelte app or a full-stack SvelteKit application, these boilerplates provide an excellent starting point.

Svelte 4 uses <slot /> and named slots like <slot name="header" /> for content projection. Svelte 5 introduces snippets — a more powerful and flexible replacement using {#snippet} blocks and {@render}. The default children are accessed via let { children } = $props(); and rendered with {@render children?.()}. Snippets support parameters, making them more versatile than traditional slots. Svelte 5 maintains backward compatibility with <slot> in most cases.
Copied to clipboard!
`; } // Template let templateLines = []; templateLines.push(`
`); if (includeProps) { templateLines.push('

{title}

'); templateLines.push('

Count: {count}

'); if (includeReactive) { templateLines.push('

Doubled: {doubledCount}

'); } templateLines.push('

Items: {itemCount}

'); } else if (includeReactive) { templateLines.push('

Counter: {counter}

'); templateLines.push('

Doubled: {doubledCounter}

'); } else { templateLines.push('

Welcome to ' + name + '

'); } if (includeSlot && includeProps) { templateLines.push(''); templateLines.push('
'); templateLines.push(' '); templateLines.push('
'); } else if (includeSlot && !includeProps && !includeReactive) { templateLines.push('
'); templateLines.push(' '); templateLines.push('
'); } if (includeProps || includeReactive) { templateLines.push(''); templateLines.push(' '); } if (includeSlot && includeProps && !includeReactive) { templateLines.push(''); templateLines.push('
'); templateLines.push(' '); templateLines.push('
'); } templateLines.push('
'); let templateBlock = templateLines.join('\n'); // Style block let styleBlock = ''; if (includeStyleDemo && styleType !== 'none') { let styleLines = []; styleLines.push(`.${toKebab(name)} {`); styleLines.push(' padding: 1rem;'); styleLines.push(' font-family: inherit;'); styleLines.push('}'); styleLines.push(''); styleLines.push(`.${toKebab(name)} h2 {`); styleLines.push(' color: #ff3e00;'); styleLines.push(' margin-bottom: 0.5rem;'); styleLines.push('}'); styleLines.push(''); styleLines.push(`.${toKebab(name)} button {`); styleLines.push(' background: #ff3e00;'); styleLines.push(' color: white;'); styleLines.push(' border: none;'); styleLines.push(' padding: 0.5rem 1.25rem;'); styleLines.push(' border-radius: 6px;'); styleLines.push(' cursor: pointer;'); styleLines.push(' font-weight: 600;'); styleLines.push(' transition: background 0.2s;'); styleLines.push('}'); styleLines.push(''); styleLines.push(`.${toKebab(name)} button:hover {`); styleLines.push(' background: #cc3200;'); styleLines.push('}'); hasStyleContent = true; styleBlock = `\n${styleLines.join('\n')}\n`; } // 组装 let parts = []; if (scriptBlock) parts.push(scriptBlock); parts.push(''); // 空行分隔 parts.push(templateBlock); if (styleBlock) { parts.push(''); parts.push(''); parts.push(styleBlock); } return parts.join('\n').trim() + '\n'; } // 生成Svelte 5代码 function generateSvelte5(config) { const { name, lang, styleType, includeProps, includeReactive, includeLifecycle, includeEvents, includeSlot, includeStyleDemo } = config; const scriptLang = lang === 'ts' ? ' lang="ts"' : ''; const styleLang = styleType === 'scss' ? ' lang="scss"' : ''; let lines = []; let hasScriptContent = false; let hasStyleContent = false; let scriptLines = []; // Props with $props() if (includeProps) { if (lang === 'ts') { scriptLines.push('interface Props {'); scriptLines.push(' title?: string;'); scriptLines.push(' count?: number;'); scriptLines.push(' items?: string[];'); if (includeEvents) scriptLines.push(' onupdate?: (data: { count: number }) => void;'); scriptLines.push('}'); scriptLines.push(''); scriptLines.push('let { title = \'Hello World\', count = 0, items = []' + (includeEvents ? ', onupdate' : '') + ' }: Props = $props();'); } else { scriptLines.push('let { title = \'Hello World\', count = 0, items = []' + (includeEvents ? ', onupdate' : '') + ' } = $props();'); } hasScriptContent = true; } else if (includeEvents) { if (lang === 'ts') { scriptLines.push('let { onupdate }: { onupdate?: (data: { count: number }) => void } = $props();'); } else { scriptLines.push('let { onupdate } = $props();'); } hasScriptContent = true; } // State if (includeReactive && !includeProps) { if (scriptLines.length > 0) scriptLines.push(''); if (lang === 'ts') { scriptLines.push('let counter = $state(0);'); } else { scriptLines.push('let counter = $state(0);'); } scriptLines.push('let doubledCounter = $derived(counter * 2);'); hasScriptContent = true; } else if (includeReactive && includeProps) { if (scriptLines.length > 0) scriptLines.push(''); scriptLines.push('let doubledCount = $derived(count * 2);'); scriptLines.push('let itemCount = $derived(items.length);'); hasScriptContent = true; } // Lifecycle via $effect if (includeLifecycle) { if (scriptLines.length > 0) scriptLines.push(''); scriptLines.push('$effect(() => {'); scriptLines.push(' // Runs on mount and when dependencies change'); scriptLines.push(' console.log(\'Component mounted or updated\');'); scriptLines.push(''); scriptLines.push(' return () => {'); scriptLines.push(' // Cleanup runs before re-run or on destroy'); scriptLines.push(' console.log(\'Cleanup\');'); scriptLines.push(' };'); scriptLines.push('});'); hasScriptContent = true; } // Helper function if (includeProps || includeReactive) { if (scriptLines.length > 0) scriptLines.push(''); scriptLines.push('function handleClick() {'); if (includeProps) { scriptLines.push(' count += 1;'); if (includeEvents) scriptLines.push(' onupdate?.({ count });'); } else if (includeReactive) { scriptLines.push(' counter += 1;'); } scriptLines.push('}'); hasScriptContent = true; } let scriptBlock = ''; if (hasScriptContent) { scriptBlock = `\n${scriptLines.join('\n')}\n`; } // Template (Svelte 5 uses onclick instead of on:click) let templateLines = []; templateLines.push(`
`); if (includeProps) { templateLines.push('

{title}

'); templateLines.push('

Count: {count}

'); if (includeReactive) { templateLines.push('

Doubled: {doubledCount}

'); } templateLines.push('

Items: {itemCount}

'); } else if (includeReactive) { templateLines.push('

Counter: {counter}

'); templateLines.push('

Doubled: {doubledCounter}

'); } else { templateLines.push('

Welcome to ' + name + '

'); } if (includeSlot) { templateLines.push(''); templateLines.push('
'); templateLines.push(' {@render children?.()}'); templateLines.push('
'); } if (includeProps || includeReactive) { templateLines.push(''); templateLines.push(' '); } templateLines.push('
'); let templateBlock = templateLines.join('\n'); // Style block let styleBlock = ''; if (includeStyleDemo && styleType !== 'none') { let styleLines = []; styleLines.push(`.${toKebab(name)} {`); styleLines.push(' padding: 1rem;'); styleLines.push(' font-family: inherit;'); styleLines.push('}'); styleLines.push(''); styleLines.push(`.${toKebab(name)} h2 {`); styleLines.push(' color: #ff3e00;'); styleLines.push(' margin-bottom: 0.5rem;'); styleLines.push('}'); styleLines.push(''); styleLines.push(`.${toKebab(name)} button {`); styleLines.push(' background: #ff3e00;'); styleLines.push(' color: white;'); styleLines.push(' border: none;'); styleLines.push(' padding: 0.5rem 1.25rem;'); styleLines.push(' border-radius: 6px;'); styleLines.push(' cursor: pointer;'); styleLines.push(' font-weight: 600;'); styleLines.push(' transition: background 0.2s;'); styleLines.push('}'); styleLines.push(''); styleLines.push(`.${toKebab(name)} button:hover {`); styleLines.push(' background: #cc3200;'); styleLines.push('}'); hasStyleContent = true; styleBlock = `\n${styleLines.join('\n')}\n`; } // 组装 let parts = []; if (scriptBlock) parts.push(scriptBlock); parts.push(''); parts.push(templateBlock); if (styleBlock) { parts.push(''); parts.push(''); parts.push(styleBlock); } return parts.join('\n').trim() + '\n'; } // 转kebab-case function toKebab(str) { return str .replace(/([a-z])([A-Z])/g, '$1-$2') .replace(/([A-Z])([A-Z][a-z])/g, '$1-$2') .replace(/[^a-zA-Z0-9-]/g, '') .toLowerCase() .replace(/--+/g, '-') .replace(/^-|-$/g, '') || 'my-component'; } // 更新预览 function updatePreview() { const config = getConfig(); let code; if (config.version === '5') { code = generateSvelte5(config); } else { code = generateSvelte4(config); } // 更新代码显示 codeOutput.textContent = code; // 更新文件名 filenameSpan.textContent = config.name + '.svelte'; // 更新badges if (config.version === '5') { badgeVersion.textContent = 'Svelte 5'; badgeVersion.className = 'badge-custom badge-svelte5'; } else { badgeVersion.textContent = 'Svelte 4'; badgeVersion.className = 'badge-custom badge-svelte4'; } if (config.lang === 'ts') { badgeLang.textContent = 'TypeScript'; badgeLang.className = 'badge-custom badge-ts'; } else { badgeLang.textContent = 'JavaScript'; badgeLang.className = 'badge-custom badge-js'; } if (config.styleType === 'scss') { badgeStyle.textContent = 'SCSS'; badgeStyle.className = 'badge-custom badge-scss'; badgeStyle.style.display = ''; } else if (config.styleType === 'none') { badgeStyle.style.display = 'none'; } else { badgeStyle.textContent = 'CSS'; badgeStyle.className = 'badge-custom badge-css'; badgeStyle.style.display = ''; } } // 显示Toast function showToast(message, iconClass = 'fa-circle-check', iconColor = '#4ade80') { if (toastTimer) clearTimeout(toastTimer); toastMsg.textContent = message; const icon = toastEl.querySelector('i'); if (icon) { icon.className = 'fa-solid ' + iconClass; icon.style.color = iconColor; } toastEl.classList.remove('d-none'); toastEl.style.opacity = '1'; toastEl.style.transform = 'translateY(0)'; toastTimer = setTimeout(() => { toastEl.style.opacity = '0'; toastEl.style.transform = 'translateY(10px)'; toastEl.style.transition = 'all 0.3s ease'; setTimeout(() => { toastEl.classList.add('d-none'); toastEl.style.transition = ''; }, 300); }, 2200); } // 复制到剪贴板 function copyToClipboard() { const code = codeOutput.textContent; if (navigator.clipboard && navigator.clipboard.writeText) { navigator.clipboard.writeText(code).then(() => { showToast('Copied to clipboard!'); }).catch(() => { fallbackCopy(code); }); } else { fallbackCopy(code); } } function fallbackCopy(text) { const textarea = document.createElement('textarea'); textarea.value = text; textarea.style.position = 'fixed'; textarea.style.opacity = '0'; document.body.appendChild(textarea); textarea.select(); try { document.execCommand('copy'); showToast('Copied to clipboard!'); } catch (e) { showToast('Failed to copy', 'fa-circle-exclamation', '#fbbf24'); } document.body.removeChild(textarea); } // 下载.svelte文件 function downloadFile() { const config = getConfig(); const code = codeOutput.textContent; const filename = config.name + '.svelte'; const blob = new Blob([code], { type: 'text/plain;charset=utf-8' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = filename; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); showToast('Downloaded ' + filename + '!'); } // 应用预设 function applyPreset(preset) { // 重置所有开关 const defaults = { 'svlt-props': false, 'svlt-reactive': false, 'svlt-lifecycle': false, 'svlt-events': false, 'svlt-slot': false, 'svlt-style-demo': true, version: '4', lang: 'js', style: 'css', name: 'MyComponent' }; switch(preset) { case 'basic': defaults['svlt-style-demo'] = true; defaults.name = 'MyComponent'; break; case 'props': defaults['svlt-props'] = true; defaults['svlt-reactive'] = true; defaults.name = 'UserCard'; break; case 'interactive': defaults['svlt-props'] = true; defaults['svlt-reactive'] = true; defaults['svlt-events'] = true; defaults['svlt-lifecycle'] = true; defaults.name = 'Counter'; break; case 'full': defaults['svlt-props'] = true; defaults['svlt-reactive'] = true; defaults['svlt-events'] = true; defaults['svlt-lifecycle'] = true; defaults['svlt-slot'] = true; defaults['svlt-style-demo'] = true; defaults.name = 'FeatureCard'; break; } // 应用设置 document.getElementById('svlt-props').checked = defaults['svlt-props']; document.getElementById('svlt-reactive').checked = defaults['svlt-reactive']; document.getElementById('svlt-lifecycle').checked = defaults['svlt-lifecycle']; document.getElementById('svlt-events').checked = defaults['svlt-events']; document.getElementById('svlt-slot').checked = defaults['svlt-slot']; document.getElementById('svlt-style-demo').checked = defaults['svlt-style-demo']; document.querySelector(`input[name="svlt-version"][value="${defaults.version}"]`).checked = true; document.querySelector(`input[name="svlt-lang"][value="${defaults.lang}"]`).checked = true; document.querySelector(`input[name="svlt-style"][value="${defaults.style}"]`).checked = true; compNameInput.value = defaults.name; // 更新预设按钮状态 document.querySelectorAll('#svlt-presets .preset-btn').forEach(b => b.classList.remove('active-preset')); const activeBtn = document.querySelector(`#svlt-presets .preset-btn[data-preset="${preset}"]`); if (activeBtn) activeBtn.classList.add('active-preset'); updatePreview(); } // 重置为默认 function resetToDefaults() { applyPreset('basic'); document.querySelectorAll('#svlt-presets .preset-btn').forEach(b => b.classList.remove('active-preset')); const basicBtn = document.querySelector('#svlt-presets .preset-btn[data-preset="basic"]'); if (basicBtn) basicBtn.classList.add('active-preset'); } // 事件监听 compNameInput.addEventListener('input', function() { updatePreview(); }); document.querySelectorAll('input[name="svlt-version"], input[name="svlt-lang"], input[name="svlt-style"]').forEach(el => { el.addEventListener('change', function() { // 清除预设激活状态(用户手动修改) document.querySelectorAll('#svlt-presets .preset-btn').forEach(b => b.classList.remove('active-preset')); updatePreview(); }); }); document.querySelectorAll('#svlt-gen .form-check-input').forEach(el => { el.addEventListener('change', function() { document.querySelectorAll('#svlt-presets .preset-btn').forEach(b => b.classList.remove('active-preset')); updatePreview(); }); }); // 预设按钮 document.querySelectorAll('#svlt-presets .preset-btn').forEach(btn => { btn.addEventListener('click', function() { const preset = this.getAttribute('data-preset'); applyPreset(preset); }); }); // 复制按钮 document.getElementById('svlt-copy-btn').addEventListener('click', copyToClipboard); // 下载按钮 document.getElementById('svlt-download-btn').addEventListener('click', downloadFile); // 重置按钮 document.getElementById('svlt-reset-btn').addEventListener('click', resetToDefaults); // 键盘快捷键 Ctrl+C / Cmd+C 在代码区复制 document.getElementById('svlt-code-container').addEventListener('keydown', function(e) { if ((e.ctrlKey || e.metaKey) && e.key === 'c') { // 如果用户选择了文本,让默认行为处理 const selection = window.getSelection(); if (selection && selection.toString().length > 0) { return; // 让默认复制行为处理 } // 否则复制全部代码 e.preventDefault(); copyToClipboard(); } }); // 初始化 updatePreview(); })();