Markup inside a Svelte component can be thought of as HTML++. You can use standard HTML elements alongside dynamic expressions and special Svelte features.
Svelte distinguishes between regular HTML elements and components based on naming:
- Lowercase tags like
<div> denote regular HTML elements
- Capitalized tags or dot notation like
<Widget> or <my.stuff> indicate components
<script>
import Widget from './Widget.svelte';
</script>
<div>
<Widget />
</div>
Element Attributes
Attributes work like their HTML counterparts, but with powerful enhancements for dynamic values.
Static Attributes
<div class="foo">
<button disabled>can't touch this</button>
</div>
Values may be unquoted:
Dynamic Attributes
Attribute values can contain JavaScript expressions:
<a href="page/{p}">page {p}</a>
Or they can be JavaScript expressions:
<button disabled={!clickable}>...</button>
Boolean and Nullish Attributes
Boolean Attributes
Included if truthy, excluded if falsy<input required={false} placeholder="Not required" />
Other Attributes
Included unless nullish (null or undefined)<div title={null}>No title attribute</div>
Attribute Shorthand
When attribute name and value match, use shorthand syntax:
<button {disabled}>...</button>
<!-- equivalent to -->
<button disabled={disabled}>...</button>
Component Props
Values passed to components are called props (not attributes):
<Widget foo={bar} answer={42} text="hello" />
Shorthand syntax works for props too:
Spread Attributes
Pass multiple attributes or props at once using spread syntax:
<Widget a="b" {...things} c="d" />
Order matters! Later attributes override earlier ones. In the example above, if things.a exists it overrides a="b", while c="d" overrides things.c.
Text Expressions
Embed JavaScript expressions in text using curly braces:
<h1>Hello {name}!</h1>
<p>{a} + {b} = {a + b}</p>
Expression Behavior
null or undefined values are omitted
- All other values are coerced to strings
- Regular expressions need parentheses:
<div>{(/^[A-Za-z ]+$/).test(value) ? x : y}</div>
Rendering HTML
Expressions are escaped by default. To render HTML, use the {@html} tag:
{@html potentiallyUnsafeHtmlString}
Always escape user-provided strings or use trusted values to prevent XSS attacks.
Use HTML comments inside components:
<!-- this is a comment! -->
<h1>Hello world</h1>
Disabling Warnings
Comments starting with svelte-ignore disable warnings for the next markup block:
<!-- svelte-ignore a11y_autofocus -->
<input bind:value={name} autofocus />
Component Documentation
Add @component comments to show documentation when hovering over component usage:
<!--
@component
- You can use markdown here
- Usage:
```html
<Main name="Arethra" />
—>
## Special Characters
Include curly braces in templates using HTML entities:
- `{` can be written as `{`, `{`, or `{`
- `}` can be written as `}`, `}`, or `}`
## Real-World Example
Here's a complete example combining multiple features:
```svelte
<script>
let name = $state('World');
let count = $state(0);
let isActive = $state(true);
</script>
<div class="container" class:active={isActive}>
<h1>Hello {name}!</h1>
<!-- Dynamic attribute -->
<button disabled={count >= 10} onclick={() => count++}>
Clicked {count} times
</button>
<!-- Attribute shorthand -->
<input bind:value={name} placeholder="Enter your name" />
</div>