Svelte File Anatomy — The Three Sections
A React component lives inside a .jsx or .tsx file: JavaScript logic at the top, a return statement wrapping JSX, and CSS either imported from a separate file or applied via CSS-in-JS. A Svelte component is a single .svelte file divided into up to three clearly labelled sections — <script>, markup, and <style> — each with a single job. Nothing is interleaved; nothing needs a build plugin to scope styles.
The three sections
Section titled “The three sections”// ProfileCard.jsximport styles from './ProfileCard.module.css';
function ProfileCard({ name, role }) { return ( <div className={styles.card}> <h2>{name}</h2> <p>{role}</p> </div> );}export default ProfileCard;<!-- ProfileCard.svelte --><script> let { name, role } = $props();</script>
<div class="card"> <h2>{name}</h2> <p>{role}</p></div>
<style> .card { border: 1px solid #ccc; padding: 1rem; border-radius: 8px; }</style>Key points:
- React keeps logic and markup entangled inside the function body. Svelte separates them into distinct sections —
<script>for logic, everything below it is the markup template. - React needs
classNamebecauseclassis a reserved JS word in JSX. Svelte markup is plain HTML — useclassas usual. - React requires a CSS Modules import (or a styled-components setup) for scoped styles. Svelte’s
<style>block is automatically scoped to the component by the compiler — no extra tooling, no class name mangling you have to manage. - React needs
export defaultto expose the component. In Svelte, the file itself is the export — the compiler handles it. \$props()in Svelte 5 replaces the destructured props argument in a React function signature.
None of the three sections are required
Section titled “None of the three sections are required”All three sections are optional. The simplest valid Svelte component is just markup:
<p>Hello, world!</p>Add <script> when you need logic, add <style> when you need styles. You only write what you need.
The markup section is the template — not a return value
Section titled “The markup section is the template — not a return value”In React, the JSX lives inside a return (...) call. Parentheses, semicolons, and the function wrapper are all load-bearing syntax. In Svelte, everything outside <script> and <style> is the template. No return, no parentheses — just write HTML.
<!-- This IS the template. No return statement. --><h1>Hello {name}</h1>Curly braces interpolate JavaScript expressions into the markup, just like JSX — but there is no surrounding function call to close.
Scoped styles with zero configuration
Section titled “Scoped styles with zero configuration”React developers typically reach for CSS Modules, styled-components, or Tailwind to avoid style leaks across components. Svelte’s <style> block is scoped by the compiler at build time. A rule like .card becomes something like .card.svelte-xyz in the output — it only matches elements inside that component file.
The practical effect: write plain CSS selectors. They will never accidentally style a .card in another component.