From ff5d36a880f6dddd7628fb2e5d6cae9ebe9c3126 Mon Sep 17 00:00:00 2001 From: paoloricciuti Date: Tue, 17 Feb 2026 12:40:56 +0100 Subject: [PATCH 01/25] docs: add best practices page to the docs --- .../97-best-practices/10-best-practices.md | 163 ++++++++++++++++++ documentation/docs/97-best-practices/index.md | 3 + 2 files changed, 166 insertions(+) create mode 100644 documentation/docs/97-best-practices/10-best-practices.md create mode 100644 documentation/docs/97-best-practices/index.md diff --git a/documentation/docs/97-best-practices/10-best-practices.md b/documentation/docs/97-best-practices/10-best-practices.md new file mode 100644 index 0000000000..ff009c4df8 --- /dev/null +++ b/documentation/docs/97-best-practices/10-best-practices.md @@ -0,0 +1,163 @@ +--- +title: Overview +--- + +This document is meant to collect a series of best practices to write not only correct but good Svelte code. The content of this page was originally created as a `SKILL.md` file but given it's content it can (and should) be used as a reference by human developers that wish to write the best possible Svelte code. + +>[!NOTE] This document will be also synchronized with the [mcp repository](https://github.com/sveltejs/mcp) to serve as a SKILL. To follow the rules of progressive discovery a few paragraph of this page that are only useful in specific situations during svelte development will merely link to other sections of the documentation. + +## State and Deriveds + +When writing a Svelte component, each variable that needs to be used inside an effect a derived or in the template must be declared with `$state`. Objects and arrays are automatically deeply reactive, and you can just mutate properties or push to them to trigger reactivity. If you are not mutating or pushing, consider using `$state.raw` to improve performance. Not every variable must be stateful, if a variable is only used to store information and never in an `$effect`, `$derived` or in the template you can avoid using `$state` completely. + +If one stateful variable depends on another stateful variable, you must use `$derived` to create this new piece of state. `$derived` accepts an expression as input. If you want to use a function, you must use `$derived.by`. Only the stateful variables that are read within a derived actually count as a dependency of that derived. This means that if you guard the read of a stateful variable with an `if`, that stateful variable will only be a dependency when the condition is true. The value of a derived can be overridden; When overridden, the value will change immediately and trigger a DOM update. But when one of the dependencies changes, the value will be recalculated and the DOM updated once again. If a component is receiving a prop and you want a piece of state to be initialised from that prop, usually it's a good idea to use a derived because if that prop is a stateful variable, when it changes, Svelte will just update the value, not remount the component; If the value could be an object, a class, or an array, the suggestion is to use `$state.snapshot` to clone them (`$state.snapshot` is using `structuredClone` under the hood so it might not always be a good idea). + +## The `$effect` rune + +`$effect` is generally considered a malpractice in Svelte. You should almost never use `$effect` to sync between stateful variables (use a `$derived` for that) and reassigning state within an `$effect` is especially bad. When encountering an `$effect` asks yourself if that's really needed. It can usually be substituted by: + +- A `$derived` +- An `@attach` +- A class that uses `createSubscriber` + +The valid use cases for `$effect` are mainly to sync svelte reactivity with a non-reactive system (like a D3 class or the local storage or inside an attachment to do imperative DOM operations). + +Like `$derived`, `$effect` automatically has every stateful variable (declared with `$state` or `$derived`) as a dependency when it's read (if you guard the read of a stateful variable with an `if`, that stateful variable will only be a dependency when the condition is true) + +If you want to log a value whenever the reactive variable changes use `$inspect` instead. + +For more information on when not to use `$effect` read [this document](/docs/svelte/$effect). + +`$effect` only runs on the client so you don't need to guard with `browser` or `typeof window === "undefined"` + +## `$bindable` + +You can use `$bindable` inside `MyComponent.svelte` like this + +```svelte + +``` + +to allow ``. This can get hairy when the value of the prop is not a literal value; try to use callbacks in that case. + +```svelte + +``` + +## `$inspect.trace` + +`$inspect.trace` is a debugging tool for reactivity. If something is not updating properly or running more than it should you can put `$inspect.trace("[yourlabel]")` as the first line of an `$effect` or `$derived.by` to get detailed logs about the dependencies of it. + +## Events on elements + +Every prop that starts with `on` is treated as an event listener for the element. To register a `click` listener on an element you can do ` + + + + + + +``` + +If you need to attach listeners to `window` or `document` you can use `` and ``: + +```svelte + + +``` + +Avoid using `onMount` or `$effect` for this. ## Each blocks From a970d20dcb3200f62f88d6a3c4c5340f6170823d Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 25 Feb 2026 13:36:10 -0500 Subject: [PATCH 25/25] godDAMMIT --- documentation/docs/07-misc/01-best-practices.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/docs/07-misc/01-best-practices.md b/documentation/docs/07-misc/01-best-practices.md index 50cb0a8131..f3864f6d2b 100644 --- a/documentation/docs/07-misc/01-best-practices.md +++ b/documentation/docs/07-misc/01-best-practices.md @@ -41,7 +41,7 @@ Effects are an escape hatch and should mostly be avoided. In particular, avoid u - If you need to sync state to an external library such as D3, it is often neater to use [`{@attach ...}`](@attach) - If you need to run some code in response to user interaction, put the code directly in an event handler or use a [function binding](bind#Function-bindings) as appropriate -- If you need to log values for debugging purposes, use [`$inspect`](inspect) +- If you need to log values for debugging purposes, use [`$inspect`]($inspect) - If you need to observe something external to Svelte, use [`createSubscriber`](svelte-reactivity#createSubscriber) Never wrap the contents of an effect in `if (browser) {...}` or similar — effects do not run on the server.