Skip to content

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.

React
// ProfileCard.jsx
import styles from './ProfileCard.module.css';
function ProfileCard({ name, role }) {
return (
<div className={styles.card}>
<h2>{name}</h2>
<p>{role}</p>
</div>
);
}
export default ProfileCard;
Svelte
<!-- 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 className because class is a reserved JS word in JSX. Svelte markup is plain HTML — use class as 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 default to 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.

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.

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.

Which section of a .svelte file is required?
How does Svelte scope component styles?
What is the Svelte equivalent of `export default function MyComp`?