You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte/documentation/docs/02-template-syntax/01-component-fundamentals.md

5.0 KiB

title
Component fundamentals
  • script (module) / template / style (rough overview)
  • $props / $state (in the context of components)

Components are the building blocks of Svelte applications. They are written into .svelte files, using a superset of HTML.

All three sections — script, styles and markup — are optional.

<script>
	// logic goes here
</script>

<!-- markup (zero or more items) goes here -->

<style>
	/* styles go here */
</style>

<script>

A <script> block contains JavaScript (or TypeScript, when adding the lang="ts" attribute) that runs when a component instance is created. Variables declared (or imported) at the top level are 'visible' from the component's markup.

Public API of a component

Svelte uses the $props rune to declare properties or props, which means describing the public interface of the component which becomes accessible to consumers of the component.

[!NOTE] $props is one of several runes, which are special hints for Svelte's compiler to make things reactive.

<script>
	let { foo, bar, baz } = $props();

	// Values that are passed in as props
	// are immediately available
	console.log({ foo, bar, baz });
</script>

You can specify a fallback value for a prop. It will be used if the component's consumer doesn't specify the prop on the component when instantiating the component, or if the passed value is undefined at some point.

<script>
	let { foo = 'optional default initial value' } = $props();
</script>

To get all properties, use rest syntax:

<script>
	let { a, b, c, ...everythingElse } = $props();
</script>

You can use reserved words as prop names.

<script>
	// creates a `class` property, even
	// though it is a reserved word
	let { class: className } = $props();
</script>

If you're using TypeScript, you can declare the prop types:

<script lang="ts">
	interface Props {
		required: string;
		optional?: number;
		[key: string]: unknown;
	}

	let { required, optional, ...everythingElse }: Props = $props();
</script>

If you're using JavaScript, you can declare the prop types using JSDoc:

<script>
	/** @type {{ x: string }} */
	let { x } = $props();

	// or use @typedef if you want to document the properties:

	/**
	 * @typedef {Object} MyProps
	 * @property {string} y Some documentation
	 */

	/** @type {MyProps} */
	let { y } = $props();
</script>

If you export a const, class or function, it is readonly from outside the component.

<script>
	export const thisIs = 'readonly';

	export function greet(name) {
		alert(`hello ${name}!`);
	}
</script>

Readonly props can be accessed as properties on the element, tied to the component using bind:this syntax.

Reactive variables

To change component state and trigger a re-render, just assign to a locally declared variable that was declared using the $state rune.

Update expressions (count += 1) and property assignments (obj.x = y) have the same effect.

<script>
	let count = $state(0);

	function handleClick() {
		// calling this function will trigger an
		// update if the markup references `count`
		count = count + 1;
	}
</script>

Svelte's <script> blocks are run only when the component is created, so assignments within a <script> block are not automatically run again when a prop updates.

<script>
	let { person } = $props();
	// this will only set `name` on component creation
	// it will not update when `person` does
	let { name } = person;
</script>

If you'd like to react to changes to a prop, use the $derived or $effect runes instead.

<script>
	let count = $state(0);

	let double = $derived(count * 2);

	$effect(() => {
		if (count > 10) {
			alert('Too high!');
		}
	});
</script>

For more information on reactivity, read the documentation around runes.

<script module>

A <script> tag with a module attribute runs once when the module first evaluates, rather than for each component instance. Values declared in this block are accessible from a regular <script> (and the component markup) but not vice versa.

You can export bindings from this block, and they will become exports of the compiled module.

You cannot export default, since the default export is the component itself.

<script module>
	let totalComponents = 0;

	// the export keyword allows this function to imported with e.g.
	// `import Example, { alertTotal } from './Example.svelte'`
	export function alertTotal() {
		alert(totalComponents);
	}
</script>

<script>
	totalComponents += 1;
	console.log(`total number of times this component has been created: ${totalComponents}`);
</script>

<style>

CSS inside a <style> block will be scoped to that component.

<style>
	p {
		/* this will only affect <p> elements in this component */
		color: burlywood;
	}
</style>

For more information regarding styling, read the documentation around styles and classes.