start updating docs

pull/1890/head
Rich Harris 7 years ago
parent 7310efc809
commit 0c7b30603e

@ -6,7 +6,7 @@ title: Introduction
Svelte is a tool for building fast web applications.
It is similar to JavaScript frameworks such as React, Angular, Vue, and Ractive, which all share a goal of making it easy to build slick interactive user interfaces.
It is similar to JavaScript frameworks such as React and Vue, which share a goal of making it easy to build slick interactive user interfaces.
But there's a crucial difference: Svelte converts your app into ideal JavaScript at *build time*, rather than interpreting your application code at *run time*. This means you don't pay the performance cost of the framework's abstractions, and you don't incur a penalty when your app first loads.
@ -17,9 +17,7 @@ You can build your entire app with Svelte, or you can add it incrementally to an
### Understanding Svelte components
In Svelte, an application is composed from one or more *components*. A component is a reusable self-contained block of code that encapsulates markup, styles and behaviours that belong together.
Like Ractive and Vue, Svelte promotes the concept of *single-file components*: a component is just an `.html` file. Here's a simple example:
In Svelte, an application is composed from one or more _components_. A component is a reusable self-contained block of code that encapsulates markup, styles and behaviours that belong together, written into an `.html` file. Here's a simple example:
```html
<!--{ title: 'Hello world!' }-->
@ -42,15 +40,15 @@ Svelte turns this into a JavaScript module that you can import into your app:
import App from './App.html';
const app = new App({
target: document.querySelector('main'),
data: { name: 'world' }
target: document.querySelector('main'),
props: { name: 'world' },
});
// change the data associated with the template
app.set({ name: 'everybody' });
// change the component's "name" prop. We'll learn about props (aka properties) below
app.name = 'everybody';
// detach the component and clean everything up
app.destroy();
app.$destroy();
```
Congratulations, you've just learned about half of Svelte's API!
@ -60,7 +58,7 @@ Congratulations, you've just learned about half of Svelte's API!
Normally, this is the part where the instructions might tell you to add the framework to your page as a `<script>` tag. But because Svelte runs at build time, it works a little bit differently.
The best way to use Svelte is to integrate it into your build system  there are plugins for Rollup, Browserify, Gulp and others, with more on the way. See [here](https://github.com/sveltejs/svelte/#svelte) for an up-to-date list.
The best way to use Svelte is to integrate it into your build system  there are plugins for Rollup, Webpack and others, with more on the way. See [here](https://github.com/sveltejs/svelte/#svelte) for an up-to-date list.
> You will need to have [Node.js](https://nodejs.org/en/) installed, and have some familiarity with the command line

@ -4,12 +4,10 @@ title: Template syntax
Rather than reinventing the wheel, Svelte templates are built on foundations that have stood the test of time: HTML, CSS and JavaScript. There's very little extra stuff to learn.
> Svelte version 1 had a slightly different template syntax. You can upgrade older components automatically using [svelte-upgrade](https://github.com/sveltejs/svelte-upgrade).
### Tags
Tags allow you to bind data to your template. Whenever your data changes (for example after `component.set(...)`), the DOM updates automatically. You can use any JavaScript expression in templates, and it will also automatically update:
Tags allow you to bind data to your template. Whenever your data changes (for example after `component.a = 3`), the DOM updates automatically. You can use any JavaScript expression in templates, and it will also automatically update:
```html
<!-- { title: 'Template tags' } -->
@ -213,33 +211,18 @@ You can use destructuring patterns on the elements of the array:
}
```
If you want to iterate over an object you can use `Object.entries(object)` which returns the object's properties as `[key, value]` pairs:
```html
<!--{ title: 'Iterating over objects' }-->
<h1>Cats and Dogs</h1>
{#each Object.entries(animals) as [animal, names]}
<p>{animal}: {names.join(" and ")}</p>
{/each}
```
```json
/* { hidden: true } */
{
animals: {
Cats: ["Buzz", "Stella"],
Dogs: ["Hector", "Victoria"]
}
}
```
### Await blocks
You can represent the three states of a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) — pending, fulfilled and rejected — with an `await` block:
```html
<!--{ title: 'Await blocks' }-->
<script>
const promise = new Promise(fulfil => {
setTimeout(() => fulfil(42), 3000);
});
</script>
{#await promise}
<p>wait for it...</p>
{:then answer}
@ -247,18 +230,6 @@ You can represent the three states of a [Promise](https://developer.mozilla.org/
{:catch error}
<p>well that's odd</p>
{/await}
<script>
export default {
data() {
return {
promise: new Promise(fulfil => {
setTimeout(() => fulfil(42), 3000);
})
};
}
};
</script>
```
If the expression in `{#await expression}` *isn't* a promise, Svelte skips ahead to the `then` section.
@ -266,12 +237,12 @@ If the expression in `{#await expression}` *isn't* a promise, Svelte skips ahead
### Directives
Directives allow you to add special instructions for adding [event handlers](guide#event-handlers), [bindings](guide#bindings), [referencing elements](guide#refs) and so on. We'll cover each of those in later stages of this guide for now, all you need to know is that directives can be identified by the `:` character:
Directives allow you to add special instructions for adding [event handlers](guide#event-handlers), [bindings](guide#bindings), [transitions](guide#transitions) and so on. We'll cover each of those in later stages of this guide for now, all you need to know is that directives can be identified by the `:` character:
```html
<!--{ title: 'Element directives' }-->
<p>Count: {count}</p>
<button on:click="set({ count: count + 1 })">+1</button>
<button on:click="{() => count += 1}">+1</button>
```
```json
@ -290,7 +261,7 @@ To inspect data as it changes and flows through your app, use a `{@debug ...}` t
```html
<!--{ title: 'Debug tags' }-->
<input bind:value=name>
<input bind:value={name}>
{@debug name}
<h1>Hello {name}!</h1>

@ -10,10 +10,6 @@ Your component template can have a `<style>` tag, like so:
```html
<!--{ title: 'Scoped styles' }-->
<div class="foo">
Big red Comic Sans
</div>
<style>
.foo {
color: red;
@ -21,6 +17,10 @@ Your component template can have a `<style>` tag, like so:
font-family: 'Comic Sans MS';
}
</style>
<div class="foo">
Big red Comic Sans
</div>
```
@ -41,9 +41,9 @@ Styles will *only* apply to the current component, unless you opt in to cascadin
```html
<!-- { repl: false } -->
<div>
<Widget/>
</div>
<script>
import Widget from './Widget.html';
</script>
<style>
p {
@ -59,13 +59,9 @@ Styles will *only* apply to the current component, unless you opt in to cascadin
}
</style>
<script>
import Widget from './Widget.html';
export default {
components: { Widget }
};
</script>
<div>
<Widget/>
</div>
```
> Scoped styles are *not* dynamic  they are shared between all instances of a component. In other words you can't use `{tags}` inside your CSS.
@ -75,27 +71,27 @@ Styles will *only* apply to the current component, unless you opt in to cascadin
Svelte will identify and remove styles that are not being used in your app. It will also emit a warning so that you can remove them from the source.
For rules *not* to be removed, they must apply to the component's markup. As far as Svelte is concerned `.active` is unused in the following code and should be removed:
For rules *not* to be removed, they must apply to the component's markup. As far as Svelte is concerned `.bold` is unused in the following code and should be removed:
```html
<!-- { repl: false } -->
<div>
<p ref:paragraph>this text is not bold</p>
<p bind:this={paragraph}>this text is not bold</p>
</div>
<style>
.active {
.bold {
color: bold;
}
</style>
<script>
export default {
oncreate() {
const { active } = this.get();
if (active) this.refs.paragraph.classList.add('active');
}
};
import { onMount } from 'svelte';
let paragraph;
onMount(() => {
paragraph.classList.add('bold');
});
</script>
```
@ -104,7 +100,7 @@ Instead of manually manipulating the DOM, you should always use the `class` attr
```html
<!-- { repl: false } -->
<div>
<p class="{active ? 'active' : ''}">this text is bold</p>
<p class:bold={bold}>this text is bold</p>
</div>
```
@ -113,30 +109,10 @@ If that's impossible for some reason, you can use `:global(...)`:
```html
<!-- { repl: false } -->
<style>
div :global(.active) {
div :global(.bold) {
color: bold;
}
</style>
```
The same applies to the contents of `{@html ...}` tags.
### Special selectors
If you have a [ref](guide#refs) on an element, you can use it as a CSS selector. The `ref:*` selector has the same specificity as a class or attribute selector.
```html
<!--{ title: 'Styling with refs' }-->
<div ref:foo>
yeah!
</div>
<style>
ref:foo {
color: magenta;
font-size: 5em;
}
</style>
```

@ -2,880 +2,120 @@
title: Behaviours
---
As well as scoped styles and a template, components can encapsulate *behaviours*. For that, we add a `<script>` element and export an object:
As well as scoped styles and a template, components can encapsulate *behaviours*. For that, we add a `<script>` element:
```html
<!-- { title: 'Behaviours' } -->
<div>
<!-- template goes here -->
</div>
<script>
export default {
// behaviours go here
};
</script>
```
### Default data
Often, it makes sense for a component to have default data. This should be expressed as a function that returns a plain JavaScript object:
```html
<!-- { title: 'Default data' } -->
<p>Count: {count}</p>
<button on:click="set({ count: count + 1 })">+1</button>
<script>
export default {
data() {
return {
count: 0
};
}
};
// behaviours go here
</script>
```
Data supplied at instantiation takes priority over defaults. In other words, if we instantiated the component above like so...
```js
const counter = new Counter({
data: {
count: 99
}
});
```
...then `{count}`, or `counter.get().count`, would initially be 99 rather than 0.
### Computed properties
Often, your program will use values that depend on other values for example, you might have a filtered list, which depends on both the list *and* the filter. Normally in JavaScript you'd have to add logic to update the dependent property when *any* of the dependencies change. This is a frequent source of bugs, and it gets worse as your application grows.
Svelte allows you to express these dependencies in computed properties, which are recalculated whenever those dependencies change:
```html
<!-- { title: 'Computed properties' } -->
<p>
The time is
<strong>{hours}:{minutes}:{seconds}</strong>
</p>
<script>
export default {
data() {
return {
time: new Date()
};
},
computed: {
hours: ({ time }) => time.getHours(),
minutes: ({ time }) => time.getMinutes(),
seconds: ({ time }) => time.getSeconds()
}
};
</script>
<div>
<!-- template goes here -->
</div>
```
Each function is passed the component's current state object. Because we're using destructuring syntax, the compiler knows that `hours`, `minutes` and `seconds` only need to re-run when `time` changes, and not when any other values change. There's no costly dependency tracking involved the dependency graph is resolved at compile time.
> `computed` must be an object literal, and the properties must be function expressions or arrow function expressions. Any external functions used in computed must be wrapped _here_:
### Internal state
```js
import externalFunc from '_external_file';
export default {
computed: {
externalFunc: ({ dep1, dep2 }) => externalFunc(dep1, dep2);
}
}
```
Computed properties can of course return functions. For example, we could dynamically generate a filter function for a list of items:
Often, it makes sense for a component to have internal state that isn't visible to the outside world.
```html
<!-- { title: 'Filtering' } -->
<input bind:value=search>
{#each items.filter(predicate) as word}
<p><strong>{word.slice(0, search.length)}</strong>{word.slice(search.length)}</p>
{:else}
<p>no matches!</p>
{/each}
<!-- { title: 'Internal state' } -->
<script>
export default {
computed: {
predicate: ({ search }) => {
search = search.toLowerCase();
return word => word.startsWith(search);
}
}
};
let count = 0;
</script>
```
```json
/* { hidden: true } */
{
search: "",
items: [
"about",
"above",
"abuse",
"actor",
"acute",
"admit",
"adopt",
"adult",
"after",
"again",
"agent",
"agree",
"ahead",
"alarm",
"album",
"alert",
"alike",
"alive",
"allow",
"alone",
"along",
"alter",
"among",
"anger",
"Angle",
"angry",
"apart",
"apple",
"apply",
"arena",
"argue",
"arise",
"array",
"aside",
"asset",
"audio",
"audit",
"avoid",
"award",
"aware",
"badly",
"baker",
"bases",
"basic",
"basis",
"beach",
"began",
"begin",
"begun",
"being",
"below",
"bench",
"billy",
"birth",
"black",
"blame",
"blind",
"block",
"blood",
"board",
"boost",
"booth",
"bound",
"brain",
"brand",
"bread",
"break",
"breed",
"brief",
"bring",
"broad",
"broke",
"brown",
"build",
"built",
"buyer",
"cable",
"calif",
"carry",
"catch",
"cause",
"chain",
"chair",
"chart",
"chase",
"cheap",
"check",
"chest",
"chief",
"child",
"china",
"chose",
"civil",
"claim",
"class",
"clean",
"clear",
"click",
"clock",
"close",
"coach",
"coast",
"could",
"count",
"court",
"cover",
"craft",
"crash",
"cream",
"crime",
"cross",
"crowd",
"crown",
"curve",
"cycle",
"daily",
"dance",
"dated",
"dealt",
"death",
"debut",
"delay",
"depth",
"doing",
"doubt",
"dozen",
"draft",
"drama",
"drawn",
"dream",
"dress",
"drill",
"drink",
"drive",
"drove",
"dying",
"eager",
"early",
"earth",
"eight",
"elite",
"empty",
"enemy",
"enjoy",
"enter",
"entry",
"equal",
"error",
"event",
"every",
"exact",
"exist",
"extra",
"faith",
"false",
"fault",
"fiber",
"field",
"fifth",
"fifty",
"fight",
"final",
"first",
"fixed",
"flash",
"fleet",
"floor",
"fluid",
"focus",
"force",
"forth",
"forty",
"forum",
"found",
"frame",
"frank",
"fraud",
"fresh",
"front",
"fruit",
"fully",
"funny",
"giant",
"given",
"glass",
"globe",
"going",
"grace",
"grade",
"grand",
"grant",
"grass",
"great",
"green",
"gross",
"group",
"grown",
"guard",
"guess",
"guest",
"guide",
"happy",
"harry",
"heart",
"heavy",
"hence",
"henry",
"horse",
"hotel",
"house",
"human",
"ideal",
"image",
"index",
"inner",
"input",
"issue",
"japan",
"jimmy",
"joint",
"jones",
"judge",
"known",
"label",
"large",
"laser",
"later",
"laugh",
"layer",
"learn",
"lease",
"least",
"leave",
"legal",
"level",
"lewis",
"light",
"limit",
"links",
"lives",
"local",
"logic",
"loose",
"lower",
"lucky",
"lunch",
"lying",
"magic",
"major",
"maker",
"march",
"maria",
"match",
"maybe",
"mayor",
"meant",
"media",
"metal",
"might",
"minor",
"minus",
"mixed",
"model",
"money",
"month",
"moral",
"motor",
"mount",
"mouse",
"mouth",
"movie",
"music",
"needs",
"never",
"newly",
"night",
"noise",
"north",
"noted",
"novel",
"nurse",
"occur",
"ocean",
"offer",
"often",
"order",
"other",
"ought",
"paint",
"panel",
"paper",
"party",
"peace",
"peter",
"phase",
"phone",
"photo",
"piece",
"pilot",
"pitch",
"place",
"plain",
"plane",
"plant",
"plate",
"point",
"pound",
"power",
"press",
"price",
"pride",
"prime",
"print",
"prior",
"prize",
"proof",
"proud",
"prove",
"queen",
"quick",
"quiet",
"quite",
"radio",
"raise",
"range",
"rapid",
"ratio",
"reach",
"ready",
"refer",
"right",
"rival",
"river",
"robin",
"roger",
"roman",
"rough",
"round",
"route",
"royal",
"rural",
"scale",
"scene",
"scope",
"score",
"sense",
"serve",
"seven",
"shall",
"shape",
"share",
"sharp",
"sheet",
"shelf",
"shell",
"shift",
"shirt",
"shock",
"shoot",
"short",
"shown",
"sight",
"since",
"sixth",
"sixty",
"sized",
"skill",
"sleep",
"slide",
"small",
"smart",
"smile",
"smith",
"smoke",
"solid",
"solve",
"sorry",
"sound",
"south",
"space",
"spare",
"speak",
"speed",
"spend",
"spent",
"split",
"spoke",
"sport",
"staff",
"stage",
"stake",
"stand",
"start",
"state",
"steam",
"steel",
"stick",
"still",
"stock",
"stone",
"stood",
"store",
"storm",
"story",
"strip",
"stuck",
"study",
"stuff",
"style",
"sugar",
"suite",
"super",
"sweet",
"table",
"taken",
"taste",
"taxes",
"teach",
"teeth",
"terry",
"texas",
"thank",
"theft",
"their",
"theme",
"there",
"these",
"thick",
"thing",
"think",
"third",
"those",
"three",
"threw",
"throw",
"tight",
"times",
"tired",
"title",
"today",
"topic",
"total",
"touch",
"tough",
"tower",
"track",
"trade",
"train",
"treat",
"trend",
"trial",
"tried",
"tries",
"truck",
"truly",
"trust",
"truth",
"twice",
"under",
"undue",
"union",
"unity",
"until",
"upper",
"upset",
"urban",
"usage",
"usual",
"valid",
"value",
"video",
"virus",
"visit",
"vital",
"voice",
"waste",
"watch",
"water",
"wheel",
"where",
"which",
"while",
"white",
"whole",
"whose",
"woman",
"women",
"world",
"worry",
"worse",
"worst",
"worth",
"would",
"wound",
"write",
"wrong",
"wrote",
"yield",
"young",
"youth"
]
}
<p>Count: {count}</p>
<button on:click="{() => count += 1}">+1</button>
```
### Lifecycle hooks
### External properties
There are four 'hooks' provided by Svelte for adding control logic — `oncreate`, `ondestroy`, `onstate` and `onupdate`:
On the other hand, for the component to form part of a system, it needs to expose certain values so that they can be set from outside. These are called *props*, and we use the `export` keyword to differentiate them from internal state:
```html
<!-- { title: 'Lifecycle hooks' } -->
<p>
The time is
<strong>{hours}:{minutes}:{seconds}</strong>
</p>
<!-- { title: 'External properties' } -->
<script>
export default {
onstate({ changed, current, previous }) {
// this fires before oncreate, and on every state change.
// the first time it runs, `previous` is undefined
if (changed.time) {
console.log(`time changed: ${previous && previous.time} -> ${current.time}`);
}
},
oncreate() {
// this fires when the component has been
// rendered to the DOM
console.log('in oncreate');
this.interval = setInterval(() => {
this.set({ time: new Date() });
}, 1000);
},
onupdate({ changed, current, previous }) {
// this fires after oncreate, and after every state change
// once the DOM is synchronised with the data
console.log(`The DOM has been updated`);
},
ondestroy() {
// this fires when the component is
// removed from the DOM
console.log('in ondestroy');
clearInterval(this.interval);
},
data() {
return {
time: new Date()
};
},
computed: {
hours: ({ time }) => time.getHours(),
minutes: ({ time }) => time.getMinutes(),
seconds: ({ time }) => time.getSeconds()
}
};
export let count = 0;
</script>
```
> You can add event listeners corresponding to `onstate`, `onupdate` and `ondestroy` programmatically — see [component.on](guide#component-on-eventname-callback-)
### Helpers
Helpers are simple functions that are used in your template. In the example above, we want to ensure that `minutes` and `seconds` are preceded with a `0` if they only have one digit, so we add a `leftPad` helper:
```html
<!-- { title: 'Helpers' } -->
<p>
The time is
<strong>{hours}:{leftPad(minutes, 2, '0')}:{leftPad(seconds, 2, '0')}</strong>
</p>
<script>
import leftPad from 'left-pad';
export default {
helpers: {
leftPad
},
oncreate() {
this.interval = setInterval(() => {
this.set({ time: new Date() });
}, 1000);
},
ondestroy() {
clearInterval(this.interval);
},
data() {
return {
time: new Date()
};
},
computed: {
hours: ({ time }) => time.getHours(),
minutes: ({ time }) => time.getMinutes(),
seconds: ({ time }) => time.getSeconds()
}
};
</script>
<p>Count: {count}</p>
<button on:click="{() => count += 1}">+1</button>
```
Of course, you could use `leftPad` inside the computed properties instead of in the template. There's no hard and fast rule about when you should use expressions with helpers versus when you should use computed properties  do whatever makes your component easier for the next developer to understand.
> Helper functions should be *pure* in other words, they should not have side-effects, and their returned value should only depend on their arguments.
> Effectively, we're exporting a *contract* with the outside world. The `export` keyword normally means something different in JavaScript, so you might be surprised to see it used like this. Just roll with it for now!
### Custom methods
In addition to the [built-in methods](guide#component-api), you can add methods of your own:
```html
<!-- { title: 'Custom methods' } -->
<p>Try calling <code>app.say('hello!')</code> from the console</p>
<script>
export default {
methods: {
say(message) {
alert(message); // again, please don't do this
}
}
};
</script>
```
These become part of the component's API:
The `= 0` sets a default value for `count`, if none is provided.
```js
import MyComponent from './MyComponent.html';
var component = new MyComponent({
target: document.querySelector('main')
const counter = new Counter({
target: document.body,
props: {
count: 99
}
});
component.say('👋');
counter.count; // 99
counter.count += 1; // 100
```
Methods (whether built-in or custom) can also be called inside [event handlers](guide#event-handlers):
Props declared with `const` or `function` are *read-only* — they cannot be set from outside. This allows you to, for example, attach custom methods to your component:
```html
<!-- { repl: false } -->
<button on:click="say('hello')">say hello!</button>
```
### Custom event handlers
Soon, we'll learn about [event handlers](guide#event-handlers) if you want, skip ahead to that section first then come back here!
Most of the time you can make do with the standard DOM events (the sort you'd add via `element.addEventListener`, such as `click`) but sometimes you might need custom events to handle gestures, for example.
Custom events are just functions that take a node and a callback as their argument, and return an object with a `destroy` method that gets called when the element is removed from the page:
```html
<!-- { title: 'Custom events' } -->
<button on:longpress="set({ done: true })">click and hold</button>
{#if done}
<p>clicked and held</p>
{/if}
<script>
export default {
events: {
longpress(node, callback) {
function onmousedown(event) {
const timeout = setTimeout(() => callback(event), 1000);
function cancel() {
clearTimeout(timeout);
node.removeEventListener('mouseup', cancel, false);
}
node.addEventListener('mouseup', cancel, false);
}
node.addEventListener('mousedown', onmousedown, false);
return {
destroy() {
node.removeEventListener('mousedown', onmousedown, false);
}
};
}
}
};
</script>
```js
component.doSomethingFun();
```
### Namespaces
### Lifecycle hooks
Components are assumed to be in the HTML namespace. If your component is designed to be used inside an `<svg>` element, you need to specify the namespace:
There are four 'hooks' provided by Svelte for adding control logic — `onMount`, `beforeUpdate`, `afterUpdate` and `onDestroy`. Import them directly from `svelte`:
```html
<!--{ title: 'SVG' }-->
<svg viewBox="0 0 1000 1000" style="width: 100%; height: 100%;">
<SmileyFace x=70 y=280 size=100 fill="#f4d9c7"/>
<SmileyFace x=800 y=250 size=150 fill="#40250f"/>
<SmileyFace x=150 y=700 size=110 fill="#d2aa7a"/>
<SmileyFace x=875 y=730 size=130 fill="#824e2e"/>
<SmileyFace x=450 y=500 size=240 fill="#d2b198"/>
</svg>
<!-- { title: 'Lifecycle hooks' } -->
<script>
import SmileyFace from './SmileyFace.html';
export default {
components: { SmileyFace }
};
import { onMount, beforeUpdate, afterUpdate, onDestroy } from 'svelte';
beforeUpdate(() => {
// this function is called immediately before
// the component updates to reflect new data
console.log(`beforeUpdate`);
});
afterUpdate(() => {
// this function is called immediately *after*
// the component updates to reflect new data.
// if you need to do anything that assumes the
// DOM is up-to-date — such as measuring the
// size of an element — do it here
console.log(`afterUpdate`);
});
onMount(() => {
// this function is called once, after the
// `afterUpdate` function (if there is one)
// runs for the first time
console.log(`onMount`);
return () => {
// this function runs when the
// component is destroyed
console.log(`onMount cleanup`);
};
});
onDestroy(() => {
// this function runs when the
// component is destroyed
console.log(`onDestroy`);
});
let count = 0;
</script>
```
```html
<!--{ filename: 'SmileyFace.html' }-->
<!-- CC-BY-SA — https://commons.wikimedia.org/wiki/File:718smiley.svg -->
<g transform="translate({x},{y}) scale({size / 366.5})">
<circle r=366.5/>
<circle r=336.5 fill={fill}/>
<path d="m-41.5 298.5c-121-21-194-115-212-233v-8l-25-1-1-18h481c6 13 10 27 13 41 13 94-38 146-114 193-45 23-93 29-142 26z"/>
<path d="m5.5 280.5c52-6 98-28 138-62 28-25 46-56 51-87 4-20 1-57-5-70l-423-1c-2 56 39 118 74 157 31 34 72 54 116 63 11 2 38 2 49 0z" fill="#871945"/>
<path d="m-290.5 -24.5c-13-26-13-57-9-85 6-27 18-52 35-68 21-20 50-23 77-18 15 4 28 12 39 23 18 17 30 40 36 67 4 20 4 41 0 60l-6 21z"/>
<path d="m-132.5 -43.5c5-6 6-40 2-58-3-16-4-16-10-10-14 14-38 14-52 0-15-18-12-41 6-55 3-3 5-5 5-6-1-4-22-8-34-7-42 4-57.6 40-66.2 77-3 17-1 53 4 59h145.2z" fill="#fff"/>
<path d="m11.5 -23.5c-2-3-6-20-7-29-5-28-1-57 11-83 15-30 41-52 72-60 29-7 57 0 82 15 26 17 45 49 50 82 2 12 2 33 0 45-1 10-5 26-8 30z"/>
<path d="m198.5 -42.5c4-5 5-34 4-50-2-14-6-24-8-24-1 0-3 2-6 5-17 17-47 13-58-9-7-16-4-31 8-43 4-4 7-8 7-9 0 0-4-2-8-3-51-17-105 20-115 80-3 15 0 43 3 53z" fill="#fff"/>
<path d="m137.5 223.5s-46 40-105 53c-66 15-114-7-114-7s14-76 93-95c76-18 126 49 126 49z" fill="#f9bedd"/>
</g>
<script>
export default {
// you can either use the shorthand 'svg', or the full
// namespace: 'http://www.w3.org/2000/svg'. (I know
// which one I prefer.)
namespace: 'svg',
<button on:click="{() => count += 1}">
Trigger an update ({count})
</button>
data() {
return {
x: 100,
y: 100,
size: 100
};
}
};
</script>
```
> Lifecycle hooks do *not* run in server-side rendering (SSR) mode, with the exception of `onDestroy`. More on SSR later.

@ -6,24 +6,18 @@ As well as containing elements (and `if` blocks and `each` blocks), Svelte compo
```html
<!-- { title: 'Nested components' } -->
<div class='widget-container'>
<Widget/>
</div>
<script>
import Widget from './Widget.html';
export default {
components: {
Widget
}
};
</script>
<div class='widget-container'>
<Widget answer={42}/>
</div>
```
```html
<!--{ filename: 'Widget.html' }-->
<p>I am a nested component</p>
<p>I am a nested component. The answer is {answer}</p>
```
That's similar to doing this...
@ -32,51 +26,21 @@ That's similar to doing this...
import Widget from './Widget.html';
const widget = new Widget({
target: document.querySelector('.widget-container')
target: document.querySelector('.widget-container'),
props: {
answer: 42
}
});
```
...except that Svelte takes care of destroying the child component when the parent is destroyed, and keeps the two components in sync with *props*.
...except that Svelte takes care of destroying the child component when the parent is destroyed, and keeps props in sync if they change.
> Component names must be capitalised, following the widely-used JavaScript convention of capitalising constructor names. It's also an easy way to distinguish components from elements in your template.
### Props
Props, short for 'properties', are the means by which you pass data down from a parent to a child component — in other words, they're just like attributes on an element:
```html
<!--{ title: 'Props' }-->
<div class='widget-container'>
<Widget foo bar="static" baz={dynamic}/>
</div>
<script>
import Widget from './Widget.html';
export default {
components: {
Widget
}
};
</script>
```
```html
<!--{ filename: 'Widget.html' }-->
<p>foo: {foo}</p>
<p>bar: {bar}</p>
<p>baz: {baz}</p>
```
```json
/* { hidden: true } */
{
dynamic: 'try changing this text'
}
```
As with element attributes, prop values can contain any valid JavaScript expression.
Props, short for 'properties', are the means by which you pass data down from a parent to a child component — in other words, they're just like attributes on an element. As with element attributes, prop values can contain any valid JavaScript expression.
Often, the name of the property will be the same as the value, in which case we can use a shorthand:
@ -96,57 +60,43 @@ A component can contain a `<slot></slot>` element, which allows the parent compo
```html
<!-- { title: 'Using <slot>' } -->
<script>
import Box from './Box.html';
</script>
<Box>
<h2>Hello!</h2>
<p>This is a box. It can contain anything.</p>
</Box>
<script>
import Box from './Box.html';
export default {
components: { Box }
};
</script>
```
```html
<!--{ filename: 'Box.html' }-->
<div class="box">
<slot><!-- content is injected here --></slot>
</div>
<style>
.box {
border: 2px solid black;
padding: 0.5em;
}
</style>
<div class="box">
<slot><!-- content is injected here --></slot>
</div>
```
The `<slot>` element can contain 'fallback content', which will be used if no children are provided for the component:
```html
<!-- { title: 'Default slot content' } -->
<Box></Box>
<script>
import Box from './Box.html';
export default {
components: { Box }
};
</script>
<Box></Box>
```
```html
<!--{ filename: 'Box.html' }-->
<div class="box">
<slot>
<p class="fallback">the box is empty!</p>
</slot>
</div>
<style>
.box {
border: 2px solid black;
@ -157,68 +107,41 @@ The `<slot>` element can contain 'fallback content', which will be used if no ch
color: #999;
}
</style>
<div class="box">
<slot>
<p class="fallback">the box is empty!</p>
</slot>
</div>
```
You can also have *named* slots. Any elements with a corresponding `slot` attribute will fill these slots:
```html
<!-- { title: 'Named slots' } -->
<script>
import ContactCard from './ContactCard.html';
</script>
<ContactCard>
<span slot="name">P. Sherman</span>
<span slot="address">42 Wallaby Way, Sydney</span>
</ContactCard>
<script>
import ContactCard from './ContactCard.html';
export default {
components: { ContactCard }
};
</script>
```
```html
<!--{ filename: 'ContactCard.html' }-->
<div class="contact-card">
<h2><slot name="name"></slot></h2>
<slot name="address">Unknown address</slot>
<br>
<slot name="email">Unknown email</slot>
</div>
<style>
.contact-card {
border: 2px solid black;
padding: 0.5em;
}
</style>
```
### Shorthand imports
As an alternative to using an `import` declaration...
```html
<!-- { repl: false } -->
<script>
import Widget from './Widget.html';
export default {
components: { Widget }
};
</script>
```
...you can write this:
```html
<!-- { repl: false } -->
<script>
export default {
components: {
Widget: './Widget.html'
}
};
</script>
<div class="contact-card">
<h2><slot name="name"></slot></h2>
<slot name="address">Unknown address</slot>
<br>
<slot name="email">Unknown email</slot>
</div>
```

@ -33,19 +33,15 @@ If you don't know what kind of component to render until the app runs — in ot
```html
<!-- { title: '<svelte:component> tags' } -->
<input type=checkbox bind:checked=foo> foo
<svelte:component this="{foo ? Red : Blue}" name="thing"/>
<script>
import Red from './Red.html';
import Blue from './Blue.html';
export default {
data() {
return { Red, Blue }
}
};
let foo = true;
</script>
<input type=checkbox bind:checked={foo}> foo
<svelte:component this="{foo ? Red : Blue}" name="thing"/>
```
```html
@ -58,56 +54,7 @@ If you don't know what kind of component to render until the app runs — in ot
<p style="color: blue">Blue {name}</p>
```
> Note that `Red` and `Blue` are items in `data`, *not* `components`, unlike if we were doing `<Red>` or `<Blue>`.
The expression inside the `this="{...}"` can be any valid JavaScript expression. For example, it could be a [computed property](guide#computed-properties):
```html
<!-- { title: '<svelte:component> with computed' } -->
<label><input type=radio bind:group=size value=small> small</label>
<label><input type=radio bind:group=size value=medium> medium</label>
<label><input type=radio bind:group=size value=large> large</label>
<svelte:component this={Size}/>
<script>
import Small from './Small.html';
import Medium from './Medium.html';
import Large from './Large.html';
export default {
computed: {
Size: ({size}) => {
if (size === 'small') return Small;
if (size === 'medium') return Medium;
return Large;
}
}
};
</script>
```
```html
<!--{ filename: 'Small.html' }-->
<p style="font-size: 12px">small</p>
```
```html
<!--{ filename: 'Medium.html' }-->
<p style="font-size: 18px">medium</p>
```
```html
<!--{ filename: 'Large.html' }-->
<p style="font-size: 32px">LARGE</p>
```
```json
/* { hidden: true } */
{
size: "medium"
}
```
The expression inside the `this="{...}"` can be any valid JavaScript expression.
### `<svelte:window>`
@ -116,13 +63,7 @@ The `<svelte:window>` tag gives you a convenient way to declaratively add event
```html
<!-- { title: '<svelte:window> tags' } -->
<svelte:window on:keydown="set({ key: event.key, keyCode: event.keyCode })"/>
{#if key}
<p><kbd>{key === ' ' ? 'Space' : key}</kbd> (code {keyCode})</p>
{:else}
<p>click in this window and press any key</p>
{/if}
<svelte:window on:keydown="{e => (key = event.key, keyCode = e.keyCode)}"/>
<style>
kbd {
@ -136,16 +77,19 @@ The `<svelte:window>` tag gives you a convenient way to declaratively add event
font-family: Inconsolata;
}
</style>
{#if key}
<p><kbd>{key === ' ' ? 'Space' : key}</kbd> (code {keyCode})</p>
{:else}
<p>click in this window and press any key</p>
{/if}
```
You can also bind to certain values — so far `innerWidth`, `outerWidth`, `innerHeight`, `outerHeight`, `scrollX`, `scrollY` and `online`:
```html
<!-- { title: '<svelte:window> bindings' } -->
<svelte:window bind:scrollY=y/>
<div class="background"></div>
<p class="fixed">user has scrolled {y} pixels</p>
<svelte:window bind:scrollY={y}/>
<style>
.background {
@ -164,11 +108,16 @@ You can also bind to certain values — so far `innerWidth`, `outerWidth`, `inne
color: white;
}
</style>
<div class="background"></div>
<p class="fixed">user has scrolled {y} pixels</p>
```
### `<svelte:document>`
TODO REPLACE THIS WITH svelte:body
The `<svelte:document>` tag, just like `<svelte:window>`, gives you a convenient way to declaratively add event listeners to the `document` object. This is useful for listening to events that don't fire on `window`, such as `mouseenter` and `mouseleave`.

@ -1,17 +1,17 @@
---
title: Directives
title: Events
---
Directives are element or component-level instructions to Svelte. They look like attributes, except with a `:` character.
In most applications, you'll need to respond to the user's actions. In Svelte, this is done with the `on:[event]` directive.
### Event handlers
### Element events
In most applications, you'll need to respond to the user's actions. In Svelte, this is done with the `on:[event]` directive.
When used on an element, `on:click={handler}` is equivalent to calling `element.addEventListener('click', handler)`. When the element is removed, Svelte calls `removeEventListener` automatically.
```html
<!-- { title: 'Event handlers' } -->
<!-- { title: 'Inline event handlers' } -->
<p>Count: {count}</p>
<button on:click="set({ count: count + 1 })">+1</button>
<button on:click="{() => count += 1}">+1</button>
```
```json
@ -21,87 +21,58 @@ In most applications, you'll need to respond to the user's actions. In Svelte, t
}
```
When the user clicks the button, Svelte calls `component.set(...)` with the provided arguments. You can call any method belonging to the component (whether [built-in](guide#component-api) or [custom](guide#custom-methods)), and any data property (or computed property) that's in scope:
For more complicated behaviours, you'll probably want to declare an event handler in your `<script>` block:
```html
<!-- { title: 'Calling custom methods' } -->
<p>Select a category:</p>
{#each categories as category}
<button on:click="select(category)">select {category}</button>
{/each}
<!-- { title: 'Event handlers' } -->
<script>
export default {
data() {
return {
categories: [
'animal',
'vegetable',
'mineral'
]
}
},
methods: {
select(name) {
alert(`selected ${name}`); // seriously, please don't do this
}
}
};
</script>
```
You can also access the `event` object in the method call:
let count = 0;
```html
<!-- { title: 'Accessing `event`' } -->
<div on:mousemove="set({ x: event.clientX, y: event.clientY })">
coords: {x},{y}
</div>
function incrementOrDecrement(event) {
const d = event.shiftKey
? -1
: +1;
<style>
div {
border: 1px solid purple;
width: 100%;
height: 100%;
count += d;
}
</style>
```
</script>
The target node can be referenced as `this`, meaning you can do this sort of thing:
<p>Count: {count}</p>
<button on:click={incrementOrDecrement}>update</button>
```
```html
<!-- { title: 'Calling node methods' } -->
<input on:focus="this.select()" value="click to select">
```json
/* { hidden: true } */
{
count: 0
}
```
### Event handler modifiers
While you can invoke methods like `event.stopPropagation` directly...
```html
<!-- { repl: false } -->
<div on:click="event.stopPropagation()">...</div>
<div on:click="{e => e.stopPropagation()}">...</div>
```
...it gets annoying if you want to combine that with some other behaviour:
```html
<!-- { repl: false } -->
<div on:click="setFoo(event)">...</div>
<script>
export default {
methods: {
setFoo(event) {
event.stopPropagation();
event.preventDefault();
this.set({ foo: true });
}
}
};
let foo = false;
function toggleFoo(event) {
event.stopPropagation();
event.preventDefault();
foo = !foo;
}
</script>
<div on:click={toggleFoo}>...</div>
```
For that reason, Svelte lets you use *event modifiers*:
@ -114,16 +85,13 @@ For that reason, Svelte lets you use *event modifiers*:
> `passive` and `once` are not implemented in `legacy` mode
The example above can be achieved with modifiers — no need for a custom method:
The example above can be achieved with modifiers — no need for a separate event handler:
```html
<!-- { repl: false } -->
<div on:click|stopPropagation|preventDefault="set({ foo: true })">...</div>
<div on:click|stopPropagation|preventDefault="{() => foo = !foo}">...</div>
```
### Custom events
You can define your own custom events to handle complex user interactions like dragging and swiping. See the earlier section on [custom event handlers](guide#custom-event-handlers) for more information.
### Component events

@ -0,0 +1,295 @@
---
title: Bindings
---
### Bindings
As we've seen, data can be passed down to elements and components with attributes and [props](guide#props). Occasionally, you need to get data back *up*; for that we use bindings.
#### Component bindings
Component bindings keep values in sync between a parent and a child:
```html
<!-- { repl: false } -->
<Widget bind:childValue=parentValue/>
```
Whenever `childValue` changes in the child component, `parentValue` will be updated in the parent component and vice versa.
If the names are the same, you can shorten the declaration:
```html
<!-- { repl: false } -->
<Widget bind:value/>
```
> Use component bindings judiciously. They can save you a lot of boilerplate, but will make it harder to reason about data flow within your application if you overuse them.
#### Element bindings
Element bindings make it easy to respond to user interactions:
```html
<!-- { title: 'Element bindings' } -->
<h1>Hello {name}!</h1>
<input bind:value=name>
```
```json
/* { hidden: true } */
{
name: 'world'
}
```
Some bindings are *one-way*, meaning that the values are read-only. Most are *two-way* — changing the data programmatically will update the DOM. The following bindings are available:
| Name | Applies to | Kind |
|-----------------------------------------------------------------|----------------------------------------------|----------------------|
| `value` | `<input>` `<textarea>` `<select>` | <span>Two-way</span> |
| `checked` `indeterminate` | `<input type=checkbox>` | <span>Two-way</span> |
| `group` (see note) | `<input type=checkbox>` `<input type=radio>` | <span>Two-way</span> |
| `currentTime` `paused` `played` `volume` | `<audio>` `<video>` | <span>Two-way</span> |
| `buffered` `duration` `seekable` | `<audio>` `<video>` | <span>One-way</span> |
| `offsetWidth` `offsetHeight` `clientWidth` `clientHeight` | All block-level elements | <span>One-way</span> |
| `scrollX` `scrollY` | `<svelte:window>` | <span>Two-way</span> |
| `online` `innerWidth` `innerHeight` `outerWidth` `outerHeight` | `<svelte:window>` | <span>One-way</span> |
> 'group' bindings allow you to capture the current value of a [set of radio inputs](repl?demo=binding-input-radio), or all the selected values of a [set of checkbox inputs](repl?demo=binding-input-checkbox-group).
Here is a complete example of using two way bindings with a form:
```html
<!-- { title: 'Form bindings' } -->
<form on:submit="handleSubmit(event)">
<input bind:value=name type=text>
<button type=submit>Say hello</button>
</form>
<script>
export default {
methods: {
handleSubmit(event) {
// prevent the page from reloading
event.preventDefault();
const { name } = this.get();
alert(`Hello ${name}!`);
}
}
};
</script>
```
```json
/* { hidden: true } */
{
name: "world"
}
```
> 'two way' bindings allow you to update a value in a nested property as seen in [checkbox input](repl?demo=binding-input-checkbox).
### Actions
Actions let you decorate elements with additional functionality. Actions are functions which may return an object with lifecycle methods, `update` and `destroy`. The action will be called when its element is added to the DOM.
Use actions for things like:
* tooltips
* lazy loading images as the page is scrolled, e.g. `<img use:lazyload data-src='giant-photo.jpg'/>`
* capturing link clicks for your client router
* adding drag and drop
```html
<!-- { title: 'Actions' } -->
<button on:click="toggleLanguage()" use:tooltip="translations[language].tooltip">
{language}
</button>
<script>
export default {
actions: {
tooltip(node, text) {
const tooltip = document.createElement('div');
tooltip.textContent = text;
Object.assign(tooltip.style, {
position: 'absolute',
background: 'black',
color: 'white',
padding: '0.5em 1em',
fontSize: '12px',
pointerEvents: 'none',
transform: 'translate(5px, -50%)',
borderRadius: '2px',
transition: 'opacity 0.4s'
});
function position() {
const { top, right, bottom } = node.getBoundingClientRect();
tooltip.style.top = `${(top + bottom) / 2}px`;
tooltip.style.left = `${right}px`;
}
function append() {
document.body.appendChild(tooltip);
tooltip.style.opacity = 0;
setTimeout(() => tooltip.style.opacity = 1);
position();
}
function remove() {
tooltip.remove();
}
node.addEventListener('mouseenter', append);
node.addEventListener('mouseleave', remove);
return {
update(text) {
tooltip.textContent = text;
position();
},
destroy() {
tooltip.remove();
node.removeEventListener('mouseenter', append);
node.removeEventListener('mouseleave', remove);
}
}
}
},
methods: {
toggleLanguage() {
const { language } = this.get();
this.set({
language: language === 'english' ? 'latin' : 'english'
});
}
}
};
</script>
```
```json
/* { hidden: true } */
{
language: "english",
translations: {
english: {
tooltip: "Switch Languages",
},
latin: {
tooltip: "Itchsway Anguageslay",
},
}
}
```
### Classes
Classes let you toggle element classes on and off. To use classes add the directive `class` followed by a colon and the class name you want toggled (`class:the-class-name="anExpression"`). The expression inside the directive's quotes will be evaluated and toggle the class on and off depending on the truthiness of the expression's result. You can only add class directives to elements.
This example adds the class `active` to `<li>` elements when the `url` property matches the path their links target.
```html
<!-- { title: 'Classes' } -->
<ul class="links">
<li class:active="url === '/'"><a href="/" on:click="goto(event)">Home</a></li>
<li class:active="url.startsWith('/blog')"><a href="/blog/" on:click="goto(event)">Blog</a></li>
<li class:active="url.startsWith('/about')"><a href="/about/" on:click="goto(event)">About</a></li>
</ul>
<script>
export default {
methods: {
goto(event) {
event.preventDefault();
this.set({ url: event.target.pathname });
}
}
}
</script>
<style>
.links {
list-style: none;
}
.links li {
float: left;
padding: 10px;
}
/* classes added this way are processed with encapsulated styles, no need for :global() */
.active {
background: #eee;
}
</style>
```
```json
/* { hidden: true } */
{
"url": "/"
}
```
Classes will work with an existing class attribute on your element. If you find yourself adding multiple ternary statements inside a class attribute, classes can simplify your component. Classes are recognized by the compiler and <a href="guide#scoped-styles">scoped correctly</a>.
If your class name is the same as a property in your component's state, you can use the shorthand of a class binding which drops the expression (`class:myProp`).
Note that class names with dashes in them do not usually make good shorthand classes since the property will also need a dash in it. The example below uses a computed property to make working with this easier, but it may be easier to not use the shorthand in cases like this.
```html
<!-- { title: 'Classes shorthand' } -->
<div class:active class:is-selected class:isAdmin>
<p>Active? {active}</p>
<p>Selected? {isSelected}</p>
</div>
<button on:click="set({ active: !active })">Toggle Active</button>
<button on:click="set({ isSelected: !isSelected })">Toggle Selected</button>
<button on:click="set({ isAdmin: !isAdmin })">Toggle Admin</button>
<script>
export default {
computed: {
// Because shorthand relfects the var name, you must use component.set({ "is-selected": true }) or use a computed
// property like this. It might be better to avoid shorthand for class names which are not valid variable names.
"is-selected": ({ isSelected }) => isSelected
}
}
</script>
<style>
div {
width: 300px;
border: 1px solid #ccc;
background: #eee;
margin-bottom: 10px;
}
.active {
background: #fff;
}
.is-selected {
border-color: #99bbff;
box-shadow: 0 0 6px #99bbff;
}
.isAdmin {
outline: 2px solid red;
}
</style>
```
```json
/* { hidden: true } */
{
"active": true,
"isSelected": false,
"isAdmin": false,
}
```

@ -1,99 +0,0 @@
---
title: Plugins
---
Svelte can be extended with plugins and extra methods.
### Transition plugins
The [svelte-transitions](https://github.com/sveltejs/svelte-transitions) package includes a selection of officially supported transition plugins, such as [fade](https://github.com/sveltejs/svelte-transitions-fade), [fly](https://github.com/sveltejs/svelte-transitions-fly) and [slide](https://github.com/sveltejs/svelte-transitions-slide). You can include them in a component like so:
```html
<!-- { title: 'svelte-transitions' } -->
<label>
<input type=checkbox bind:checked=visible> visible
</label>
{#if visible}
<!-- use `in`, `out`, or `transition` (bidirectional) -->
<div transition:fly="{y:20}">hello!</div>
{/if}
<script>
import { fly } from 'svelte-transitions';
export default {
transitions: { fly }
};
</script>
```
```json
/* { hidden: true } */
{
visible: true
}
```
### Extra methods
The [svelte-extras](https://github.com/sveltejs/svelte-extras) package includes a handful of methods for tweening (animating), manipulating arrays and so on.
```html
<!-- { title: 'svelte-extras' } -->
<input bind:value=newTodo placeholder="buy milk">
<button on:click="push('todos', newTodo)">add todo</button>
<ul>
{#each todos as todo, i}
<li>
<button on:click="splice('todos', i, 1)">x</button>
{todo}
</li>
{/each}
</ul>
<style>
ul {
list-style: none;
padding: 0;
}
li button {
color: rgb(200,0,0);
background: rgba(200,0,0,0.1);
border-color: rgba(200,0,0,0.2);
padding: 0.2em 0.5em;
}
</style>
<script>
import { push, splice } from 'svelte-extras';
export default {
data() {
return {
newTodo: '',
todos: []
};
},
methods: {
push,
splice
}
};
</script>
```
```json
/* { hidden: true } */
{
todos: [
"wash the car",
"take the dog for a walk",
"mow the lawn"
]
}
```

@ -0,0 +1,89 @@
---
title: Transitions
---
### Transitions
Transitions allow elements to enter and leave the DOM gracefully, rather than suddenly appearing and disappearing.
```html
<!-- { title: 'Transitions' } -->
<script>
import { fade } from 'svelte/transition.js';
let visible = false;
</script>
<input type=checkbox bind:checked={visible}> visible
{#if visible}
<p transition:fade>fades in and out</p>
{/if}
```
Transitions can have parameters — typically `delay` and `duration`, but often others, depending on the transition in question. For example, here's the `fly` transition from the [svelte-transitions](https://github.com/sveltejs/svelte-transitions) package:
```html
<!-- { title: 'Transition with parameters' } -->
<script>
import { fly } from 'svelte-transitions';
let visible = false;
</script>
<input type=checkbox bind:checked={visible}> visible
{#if visible}
<p transition:fly="{{y: 200, duration: 1000}}">flies 200 pixels up, slowly</p>
{/if}
```
An element can have separate `in` and `out` transitions:
```html
<!-- { title: 'Transition in/out' } -->
<script>
import { fade, fly } from 'svelte-transitions';
let visible = false;
</script>
<input type=checkbox bind:checked={visible}> visible
{#if visible}
<p in:fly="{y: 50}" out:fade>flies up, fades out</p>
{/if}
```
Transitions are simple functions that take a `node` and any provided `parameters` and return an object with the following properties:
* `duration` — how long the transition takes in milliseconds
* `delay` — milliseconds before the transition starts
* `easing` — an [easing function](https://github.com/rollup/eases-jsnext)
* `css` — a function that accepts an argument `t` between 0 and 1 and returns the styles that should be applied at that moment
* `tick` — a function that will be called on every frame, with the same `t` argument, while the transition is in progress
Of these, `duration` is required, as is *either* `css` or `tick`. The rest are optional. Here's how the `fade` transition is implemented, for example:
```html
<!-- { title: 'Fade transition' } -->
<script>
function fade(node, { delay = 0, duration = 400 }) {
const o = +getComputedStyle(node).opacity;
return {
delay,
duration,
css: t => `opacity: ${t * o}`
};
}
let visible = false;
</script>
<input type=checkbox bind:checked={visible}> visible
{#if visible}
<p transition:fade>fades in and out</p>
{/if}
```
> If the `css` option is used, Svelte will create a CSS animation that runs efficiently off the main thread. Therefore if you can achieve an effect using `css` rather than `tick`, you should.

@ -0,0 +1,103 @@
---
title: Actions
---
### Actions
Actions let you decorate elements with additional functionality. Actions are functions which may return an object with lifecycle methods, `update` and `destroy`. The action will be called when its element is added to the DOM.
Use actions for things like:
* tooltips
* lazy loading images as the page is scrolled, e.g. `<img use:lazyload data-src='giant-photo.jpg'/>`
* capturing link clicks for your client router
* adding drag and drop
```html
<!-- { title: 'Actions' } -->
<button on:click={toggleLanguage} use:tooltip={translations[language].tooltip}>
{language}
</button>
<script>
export default {
actions: {
tooltip(node, text) {
const tooltip = document.createElement('div');
tooltip.textContent = text;
Object.assign(tooltip.style, {
position: 'absolute',
background: 'black',
color: 'white',
padding: '0.5em 1em',
fontSize: '12px',
pointerEvents: 'none',
transform: 'translate(5px, -50%)',
borderRadius: '2px',
transition: 'opacity 0.4s'
});
function position() {
const { top, right, bottom } = node.getBoundingClientRect();
tooltip.style.top = `${(top + bottom) / 2}px`;
tooltip.style.left = `${right}px`;
}
function append() {
document.body.appendChild(tooltip);
tooltip.style.opacity = 0;
setTimeout(() => tooltip.style.opacity = 1);
position();
}
function remove() {
tooltip.remove();
}
node.addEventListener('mouseenter', append);
node.addEventListener('mouseleave', remove);
return {
update(text) {
tooltip.textContent = text;
position();
},
destroy() {
tooltip.remove();
node.removeEventListener('mouseenter', append);
node.removeEventListener('mouseleave', remove);
}
}
}
},
methods: {
toggleLanguage() {
const { language } = this.get();
this.set({
language: language === 'english' ? 'latin' : 'english'
});
}
}
};
</script>
```
```json
/* { hidden: true } */
{
language: "english",
translations: {
english: {
tooltip: "Switch Languages",
},
latin: {
tooltip: "Itchsway Anguageslay",
},
}
}
```

@ -0,0 +1,70 @@
---
title: Classes
---
Like any attribute, the `class` attribute can be set using regular JavaScript. Suppose we had an `active` class that we wanted to apply to an element when `isActive` is true — we could do it like this:
```html
<!-- { title: 'Dynamic classes using ternaries' } -->
<script>
let isActive = false;
</script>
<style>
.active {
color: red;
}
</style>
<h1 class="{isActive ? 'active' : ''}">red if active</h1>
<label>
<input type=checkbox bind:checked={isActive}> isActive
</label>
```
That's a little verbose though, so the `class:` directive gives you a simpler way to achieve the same thing:
```diff
<!-- { title: 'Dynamic classes using directives' } -->
<script>
let isActive = false;
</script>
<style>
.active {
color: red;
}
</style>
-<h1 class="{isActive ? 'active' : ''}">red if active</h1>
+<h1 class:active={isActive}>red if active</h1>
<label>
<input type=checkbox bind:checked={isActive}> isActive
</label>
```
As with any directive, you can use any JavaScript expression. If it's a variable name that matches the class name, you can use a shorthand:
```diff
<!-- { title: 'Dynamic classes using directives' } -->
<script>
- let isActive = false;
+ let active = false;
</script>
<style>
.active {
color: red;
}
</style>
-<h1 class:active={isActive}>red if active</h1>
+<h1 class:active>red if active</h1>
<label>
- <input type=checkbox bind:checked={isActive}> isActive
+ <input type=checkbox bind:checked={active}> active
</label>
```

@ -1,14 +1,16 @@
---
title: Component API
title: API reference
---
## TODO MAKE THIS CURRENT, INCLUDE svelte, svelte/store, ETC ETC
As we saw above, you create a component instance with the `new` keyword:
```js
/* { filename: 'main.js' } */
import MyComponent from './MyComponent.html';
import App from './App.html';
const component = new MyComponent({
const component = new App({
// `target` is the only required option. This is the
// DOM element your component will be appended to
target: document.querySelector('main'),
@ -18,9 +20,9 @@ const component = new MyComponent({
// DOM element, which must be a child of `target`
anchor: document.querySelector('main #child'),
// `data` is optional.
// A component can have default data we'll learn about that later.
data: {
// `props` is optional. A component can also have
// default props we'll learn about that later.
props: {
questions: [
'life',
'the universe',
@ -31,10 +33,16 @@ const component = new MyComponent({
});
```
Every Svelte component instance has a small number of methods you can use to control it, in addition to any [custom methods](guide#custom-methods) you add.
Normally, you'd interact with a component by getting and setting *props*:
```js
console.log(component.answer); // 42
component.answer =
Every Svelte component instance has three built-in methods:
### component.set(state)
### component.$set(props)
This updates the component's state with the new values provided and causes the DOM to update. `state` must be a plain old JavaScript object (POJO). Any properties *not* included in `state` will remain as they were.
Loading…
Cancel
Save