The Bottom Line
Footers contain secondary navigation, legal links, contact info, and copyright notices. Like headers, they belong in the layout so they appear consistently across all pages.
What You’ll Learn
- Add a footer below the page content
- Include common footer elements
- Complete the basic layout structure
Add the Footer
Update your layout to include a footer after <main>:
<!-- filename: src/routes/+layout.svelte -->
<script>
let { children } = $props();
</script>
<div class="app">
<header>
<nav>
<a href="/" class="logo">BookIt</a>
<ul>
<li><a href="/services">Services</a></li>
<li><a href="/about">About</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
</nav>
</header>
<main>
{@render children()}
</main>
<footer>
<div class="footer-content">
<div class="footer-section">
<h4>BookIt</h4>
<p>Simple online booking for local services.</p>
</div>
<div class="footer-section">
<h4>Quick Links</h4>
<ul>
<li><a href="/services">Services</a></li>
<li><a href="/about">About</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
</div>
<div class="footer-section">
<h4>Contact</h4>
<p>hello@bookit.example</p>
<p>(555) 123-4567</p>
</div>
</div>
<div class="footer-bottom">
<p>© {new Date().getFullYear()} BookIt. All rights reserved.</p>
</div>
</footer>
</div> The footer includes:
- Brand description
- Quick navigation links
- Contact information
- Copyright with dynamic year
Style the Footer
Add footer styles to your existing <style> block:
<style>
/* ... existing header/nav/main styles ... */
footer {
background: #333;
color: #fff;
padding: 2rem 1rem 1rem;
margin-top: auto;
}
.footer-content {
display: flex;
flex-wrap: wrap;
gap: 2rem;
max-width: 1200px;
margin: 0 auto;
}
.footer-section {
flex: 1;
min-width: 200px;
}
.footer-section h4 {
margin: 0 0 1rem 0;
font-size: 1rem;
}
.footer-section p {
margin: 0.5rem 0;
color: #aaa;
}
.footer-section ul {
list-style: none;
padding: 0;
margin: 0;
}
.footer-section li {
margin: 0.5rem 0;
}
.footer-section a {
color: #aaa;
text-decoration: none;
}
.footer-section a:hover {
color: #fff;
}
.footer-bottom {
border-top: 1px solid #444;
margin-top: 2rem;
padding-top: 1rem;
text-align: center;
max-width: 1200px;
margin-left: auto;
margin-right: auto;
}
.footer-bottom p {
margin: 0;
color: #888;
font-size: 0.875rem;
}
</style> Dynamic Copyright Year
Notice this line:
<p>© {new Date().getFullYear()} BookIt. All rights reserved.</p> The {new Date().getFullYear()} expression runs JavaScript to get the current year. When 2025 becomes 2026, the footer automatically updates. No manual changes needed.
Test the Complete Layout
Visit any page. You should see:
- Header — Logo and navigation at top
- Main — Page-specific content in the middle
- Footer — Site info and links at bottom
Scroll to the bottom of short pages — the footer should be at the bottom of the viewport (thanks to margin-top: auto on footer and flexbox on .app).
The Complete Layout
Here’s the full +layout.svelte:
<!-- filename: src/routes/+layout.svelte -->
<script>
let { children } = $props();
</script>
<div class="app">
<header>
<nav>
<a href="/" class="logo">BookIt</a>
<ul>
<li><a href="/services">Services</a></li>
<li><a href="/about">About</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
</nav>
</header>
<main>
{@render children()}
</main>
<footer>
<div class="footer-content">
<div class="footer-section">
<h4>BookIt</h4>
<p>Simple online booking for local services.</p>
</div>
<div class="footer-section">
<h4>Quick Links</h4>
<ul>
<li><a href="/services">Services</a></li>
<li><a href="/about">About</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
</div>
<div class="footer-section">
<h4>Contact</h4>
<p>hello@bookit.example</p>
<p>(555) 123-4567</p>
</div>
</div>
<div class="footer-bottom">
<p>© {new Date().getFullYear()} BookIt. All rights reserved.</p>
</div>
</footer>
</div>
<style>
.app {
min-height: 100vh;
display: flex;
flex-direction: column;
}
header {
background: #f8f9fa;
border-bottom: 1px solid #e9ecef;
padding: 1rem;
}
nav {
display: flex;
justify-content: space-between;
align-items: center;
max-width: 1200px;
margin: 0 auto;
}
.logo {
font-size: 1.5rem;
font-weight: bold;
text-decoration: none;
color: #333;
}
header ul {
display: flex;
gap: 1.5rem;
list-style: none;
margin: 0;
padding: 0;
}
header li a {
text-decoration: none;
color: #666;
}
header li a:hover {
color: #333;
}
main {
flex: 1;
padding: 2rem;
max-width: 1200px;
margin: 0 auto;
width: 100%;
}
footer {
background: #333;
color: #fff;
padding: 2rem 1rem 1rem;
margin-top: auto;
}
.footer-content {
display: flex;
flex-wrap: wrap;
gap: 2rem;
max-width: 1200px;
margin: 0 auto;
}
.footer-section {
flex: 1;
min-width: 200px;
}
.footer-section h4 {
margin: 0 0 1rem 0;
font-size: 1rem;
}
.footer-section p {
margin: 0.5rem 0;
color: #aaa;
}
.footer-section ul {
list-style: none;
padding: 0;
margin: 0;
}
.footer-section li {
margin: 0.5rem 0;
}
.footer-section a {
color: #aaa;
text-decoration: none;
}
.footer-section a:hover {
color: #fff;
}
.footer-bottom {
border-top: 1px solid #444;
margin-top: 2rem;
padding-top: 1rem;
text-align: center;
max-width: 1200px;
margin-left: auto;
margin-right: auto;
}
.footer-bottom p {
margin: 0;
color: #888;
font-size: 0.875rem;
}
</style> Common Mistakes
Footer Before {@render children()}
<!-- ❌ Footer appears above page content -->
<footer>...</footer>
{@render children()}
<!-- ✅ Footer appears below page content -->
{@render children()}
<footer>...</footer> Order matters. Content renders in the order it appears in your layout.
Hardcoding the Year
<!-- ❌ Needs manual update every year -->
<p>© 2025 BookIt</p>
<!-- ✅ Always current -->
<p>© {new Date().getFullYear()} BookIt</p> Dynamic year means one less thing to maintain.
Summary
BookIt now has a complete layout with header and footer. Every page automatically gets consistent navigation and site information without any page-level code.
Key takeaways:
- Footer goes after
{@render children()}in the layout - Use semantic
<footer>element for accessibility - Dynamic expressions like
{new Date().getFullYear()}keep content current
Next Steps
The root layout wraps everything, but sometimes sections need additional wrapping. Continue with Nested Layouts to learn how the services section can have its own sub-navigation.