The Anatomy of a Component
Every Svelte component lives in a .svelte file. These files have a simple structure that keeps your logic, markup, and styles together in one place. Understanding this structure is fundamental to everything we’ll build in BookIt.
What You’ll Learn
- The three sections of a
.sveltefile - How script, markup, and style work together
- Why colocating everything in one file is powerful
Open Your First Component
Let’s look at the homepage SvelteKit generated. Open src/routes/+page.svelte:
<!-- filename: src/routes/+page.svelte -->
<h1>Welcome to SvelteKit</h1>
<p>Visit <a href="https://svelte.dev/docs/kit">svelte.dev/docs/kit</a> to read the documentation</p> This is the simplest possible Svelte component — just HTML markup. But most components have three sections.
The Three Sections
A complete Svelte component can have up to three sections:
<script>
// JavaScript logic goes here
</script>
<!-- HTML markup goes here -->
<style>
/* CSS styles go here */
</style> Let’s look at each one.
The Script Section
The <script> tag contains your component’s JavaScript. This is where you define variables, import other components, and write logic.
<script>
import ServiceCard from '$lib/components/ServiceCard.svelte'
let name = 'BookIt'
let serviceCount = 5
</script> Variables defined here are available in your markup. We’ll add reactivity to these variables in Module 4, but for now, think of them as regular JavaScript variables.
The Markup Section
The markup section is HTML with superpowers. It sits between the <script> and <style> tags (or can be the entire file if you don’t need the others).
You can use curly braces {} to insert JavaScript values:
<script>
let name = 'BookIt'
</script>
<h1>Welcome to {name}</h1>
<p>We have {5 * 2} services available</p> This renders:
- Welcome to BookIt
- We have 10 services available
Anything inside {} is JavaScript — variables, expressions, function calls. The compiler handles updating the DOM when values change.
The Style Section
The <style> tag contains CSS that’s automatically scoped to this component. Styles here won’t leak out and affect other parts of your app.
<script>
let name = 'BookIt'
</script>
<h1>Welcome to {name}</h1>
<style>
h1 {
color: #2563eb;
font-size: 2rem;
}
</style> That h1 style only applies to the <h1> in this component. If another component has an <h1>, it won’t be affected. This scoping is automatic — you don’t need to invent unique class names or use CSS modules.
A Real Example
Let’s see how these sections work together in a component we’ll build for BookIt. Here’s a preview of a service card:
<!-- filename: src/lib/components/ServiceCard.svelte -->
<script>
let { name, price, duration } = $props()
</script>
<article class="card">
<h3>{name}</h3>
<p class="price">${price}</p>
<p class="duration">{duration} minutes</p>
</article>
<style>
.card {
padding: 1.5rem;
border: 1px solid #e5e7eb;
border-radius: 8px;
background: white;
}
h3 {
margin: 0 0 0.5rem;
font-size: 1.25rem;
}
.price {
font-weight: 600;
color: #059669;
}
.duration {
color: #6b7280;
font-size: 0.875rem;
}
</style> Notice how everything related to this component lives in one file:
- Script: Receives
name,price, anddurationas props (we’ll cover$props()in Module 7) - Markup: Uses those values in the HTML structure
- Style: Defines how the card looks, scoped to this component only
Section Order Doesn’t Matter
You can arrange the sections in any order. These are all valid:
<!-- Script first (most common) -->
<script>...</script>
<div>...</div>
<style>...</style>
<!-- Style first -->
<style>...</style>
<script>...</script>
<div>...</div>
<!-- Markup first -->
<div>...</div>
<script>...</script>
<style>...</style> Most developers put <script> first because you typically want to see the data and logic before the markup that uses it. But it’s a matter of preference.
Sections Are Optional
You only need to include the sections you use:
<!-- Just markup — valid -->
<h1>Hello</h1>
<!-- Markup and style, no script — valid -->
<h1>Hello</h1>
<style>
h1 { color: blue; }
</style>
<!-- Script and markup, no style — valid -->
<script>
let name = 'World'
</script>
<h1>Hello {name}</h1> Start with what you need. Add sections as your component grows.
Why Colocation Works
Keeping script, markup, and styles in one file might feel unusual if you’re used to separating HTML, CSS, and JavaScript. But there’s a good reason Svelte (and modern React, Vue) do it this way.
A component is a unit of UI. Everything about that unit — its logic, structure, and appearance — belongs together. When you need to change how a service card looks, you open one file, not three.
This is especially powerful as your app grows. BookIt will have dozens of components. Finding and updating them is straightforward when each component is self-contained.
Common Mistakes
Forgetting Curly Braces
<script>
let name = 'BookIt'
</script>
<!-- ❌ Wrong — displays literal text "name" -->
<h1>Welcome to name</h1>
<!-- ✅ Correct — displays "BookIt" -->
<h1>Welcome to {name}</h1> If you see variable names appearing literally in your page, you forgot the curly braces.
Using JavaScript Keywords as Variable Names
<script>
// ❌ Wrong — "class" is a reserved word
let class = 'premium'
// ✅ Correct — use a different name
let tier = 'premium'
</script> Summary
Svelte components live in .svelte files with three optional sections: <script> for JavaScript logic, markup for HTML structure, and <style> for scoped CSS. Curly braces {} let you insert JavaScript values into your markup.
Key takeaways:
- Script holds logic, markup holds structure, style holds appearance
- Use
{variable}to insert JavaScript values into HTML - Styles are automatically scoped to the component
- All three sections are optional — use what you need
Next Steps
You understand the structure of a Svelte component. In the next lesson, Run Your First Dev Server, we’ll make sure your development environment is set up for a smooth workflow as we build BookIt.