diff --git a/site/content/guide/00-introduction.md b/site/content/guide/00-introduction.md index 6892832989..04ec1b7a8c 100644 --- a/site/content/guide/00-introduction.md +++ b/site/content/guide/00-introduction.md @@ -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 @@ -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 ` + {#await promise}

wait for it...

{:then answer} @@ -247,18 +230,6 @@ You can represent the three states of a [Promise](https://developer.mozilla.org/ {:catch error}

well that's odd

{/await} - - ``` 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

Count: {count}

- + ``` ```json @@ -290,7 +261,7 @@ To inspect data as it changes and flows through your app, use a `{@debug ...}` t ```html - + {@debug name}

Hello {name}!

diff --git a/site/content/guide/03-scoped-styles.md b/site/content/guide/03-scoped-styles.md index ca8a53a5b4..9a96da84db 100644 --- a/site/content/guide/03-scoped-styles.md +++ b/site/content/guide/03-scoped-styles.md @@ -10,10 +10,6 @@ Your component template can have a ` + +
+ Big red Comic Sans +
``` @@ -41,9 +41,9 @@ Styles will *only* apply to the current component, unless you opt in to cascadin ```html -
- -
+ - +
+ +
``` > 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
-

this text is not bold

+

this text is not bold

``` @@ -104,7 +100,7 @@ Instead of manually manipulating the DOM, you should always use the `class` attr ```html
-

this text is bold

+

this text is bold

``` @@ -113,30 +109,10 @@ If that's impossible for some reason, you can use `:global(...)`: ```html ``` -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 - -
- yeah! -
- - -``` +The same applies to the contents of `{@html ...}` tags. \ No newline at end of file diff --git a/site/content/guide/04-behaviour.md b/site/content/guide/04-behaviour.md index ca9fea021b..008a6e4556 100644 --- a/site/content/guide/04-behaviour.md +++ b/site/content/guide/04-behaviour.md @@ -2,880 +2,120 @@ title: Behaviours --- -As well as scoped styles and a template, components can encapsulate *behaviours*. For that, we add a ` -``` - - -### 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 - -

Count: {count}

- - -``` - -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 - -

- The time is - {hours}:{minutes}:{seconds} -

- - +
+ +
``` -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 - - - -{#each items.filter(predicate) as word} -

{word.slice(0, search.length)}{word.slice(search.length)}

-{:else} -

no matches!

-{/each} - + -``` -```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" - ] -} +

Count: {count}

+ ``` -### 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 - -

- The time is - {hours}:{minutes}:{seconds} -

- + -``` - -> 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 - -

- The time is - {hours}:{leftPad(minutes, 2, '0')}:{leftPad(seconds, 2, '0')} -

- - +

Count: {count}

+ ``` -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 - -

Try calling app.say('hello!') from the console

- - -``` - -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 - - -``` - - -### 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 - - - -{#if done} -

clicked and held

-{/if} - - +```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 `` 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 - - - - - - - - - + -``` - -```html - - - - - - - - - - - - - - -``` +> Lifecycle hooks do *not* run in server-side rendering (SSR) mode, with the exception of `onDestroy`. More on SSR later. diff --git a/site/content/guide/05-nested-components.md b/site/content/guide/05-nested-components.md index 275406dfd9..be114b49eb 100644 --- a/site/content/guide/05-nested-components.md +++ b/site/content/guide/05-nested-components.md @@ -6,24 +6,18 @@ As well as containing elements (and `if` blocks and `each` blocks), Svelte compo ```html -
- -
- + +
+ +
``` ```html -

I am a nested component

+

I am a nested component. The answer is {answer}

``` 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 - -
- -
- - -``` - -```html - -

foo: {foo}

-

bar: {bar}

-

baz: {baz}

-``` - -```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 `` element, which allows the parent compo ```html + +

Hello!

This is a box. It can contain anything.

- - ``` ```html -
- -
- + +
+ +
``` The `` element can contain 'fallback content', which will be used if no children are provided for the component: ```html - - + + ``` ```html -
- -

the box is empty!

-
-
- + +
+ +

the box is empty!

+
+
``` You can also have *named* slots. Any elements with a corresponding `slot` attribute will fill these slots: ```html + + P. Sherman 42 Wallaby Way, Sydney - - ``` ```html -
-

- Unknown address -
- Unknown email -
- -``` - - -### Shorthand imports - -As an alternative to using an `import` declaration... - -```html - - -``` - -...you can write this: -```html - - +
+

+ Unknown address +
+ Unknown email +
``` \ No newline at end of file diff --git a/site/content/guide/06-special-components.md b/site/content/guide/06-special-components.md index 95d8dff201..47c31c3733 100644 --- a/site/content/guide/06-special-components.md +++ b/site/content/guide/06-special-components.md @@ -33,19 +33,15 @@ If you don't know what kind of component to render until the app runs — in ot ```html - foo - - + + foo + ``` ```html @@ -58,56 +54,7 @@ If you don't know what kind of component to render until the app runs — in ot

Blue {name}

``` -> Note that `Red` and `Blue` are items in `data`, *not* `components`, unlike if we were doing `` or ``. - -The expression inside the `this="{...}"` can be any valid JavaScript expression. For example, it could be a [computed property](guide#computed-properties): - -```html - - - - - - - - -``` - -```html - -

small

-``` - -```html - -

medium

-``` - -```html - -

LARGE

-``` - -```json -/* { hidden: true } */ -{ - size: "medium" -} -``` +The expression inside the `this="{...}"` can be any valid JavaScript expression. ### `` @@ -116,13 +63,7 @@ The `` tag gives you a convenient way to declaratively add event ```html - - -{#if key} -

{key === ' ' ? 'Space' : key} (code {keyCode})

-{:else} -

click in this window and press any key

-{/if} + + +{#if key} +

{key === ' ' ? 'Space' : key} (code {keyCode})

+{:else} +

click in this window and press any key

+{/if} ``` You can also bind to certain values — so far `innerWidth`, `outerWidth`, `innerHeight`, `outerHeight`, `scrollX`, `scrollY` and `online`: ```html - - -
-

user has scrolled {y} pixels

+ + +
+

user has scrolled {y} pixels

``` ### `` +TODO REPLACE THIS WITH svelte:body + The `` tag, just like ``, 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`. diff --git a/site/content/guide/07-element-directives.md b/site/content/guide/07-events.md similarity index 89% rename from site/content/guide/07-element-directives.md rename to site/content/guide/07-events.md index 310ecaa419..11c8c18f9f 100644 --- a/site/content/guide/07-element-directives.md +++ b/site/content/guide/07-events.md @@ -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 - +

Count: {count}

- + ``` ```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 ` -``` - -You can also access the `event` object in the method call: + let count = 0; -```html - -
- coords: {x},{y} -
+ function incrementOrDecrement(event) { + const d = event.shiftKey + ? -1 + : +1; - -``` + -The target node can be referenced as `this`, meaning you can do this sort of thing: +

Count: {count}

+ +``` -```html - - +```json +/* { hidden: true } */ +{ + count: 0 +} ``` + ### Event handler modifiers While you can invoke methods like `event.stopPropagation` directly... ```html -
...
+
...
``` ...it gets annoying if you want to combine that with some other behaviour: ```html -
...
- + +
...
``` 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 -
...
+
...
``` -### 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 diff --git a/site/content/guide/08-bindings.md b/site/content/guide/08-bindings.md new file mode 100644 index 0000000000..943713682d --- /dev/null +++ b/site/content/guide/08-bindings.md @@ -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 + + +``` + +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 + + +``` + +> 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 + +

Hello {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` | `` `