Svelte 50 Projects 50 Days - Project 1 Expanding Card
Mohammad Saiful Islam
Posted on October 23, 2021
Learning a new JavaScript framework 50projects50days is a great resource. We can convert them to the new framework. Nowadays Svelte is one of the hot UI frameworks (actually it's a build-time compiler). I decided I convert those projects to Svelte. So I'm going to make our first project Expanding Cards in Svelte. For this project, we can use Svelte REPL. Here we can do live code. So let's start.
A Svelte component has 3 parts. script
, template
, style
.
<script>
//JavaScipt logic goes here
</script>
<!-- HTML content goes here -->
<style>
/* style goes here */
</style>
So let's implement the template
part.
Making Template
<main>
<div class="container">
<div class="panel" style="background-image: url('https://images.unsplash.com/photo-1558979158-65a1eaa08691?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80')">
<h3>Explore The World</h3>
</div>
</div>
</main>
And the style
part.
<style>
@import url('https://fonts.googleapis.com/css?family=Muli&display=swap');
* {
box-sizing: border-box;
}
main {
font-family: 'Muli', sans-serif;
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
overflow: hidden;
margin: 0;
}
.container {
display: flex;
width: 90vw;
}
.panel {
height: 80vh;
border-radius: 25px;
color: #fff;
flex: 1;
cursor: pointer;
margin: 10px;
position: relative;
background-size: cover;
background-position: center;
background-repeat: no-repeat;
}
.panel h3 {
font-size: 24px;
position: absolute;
bottom: 20px;
left: 20px;
margin: 0;
opacity: 0;
}
</style>
And it looks like this.
Now we are going to add 5 photos in the container
and the first panel should have an active
class, and also for the active class add some CSS.
<div class="panel active" style="background-image: url('https://images.unsplash.com/photo-1558979158-65a1eaa08691?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80')">
<h3>Explore The World</h3>
</div>
<div class="panel" style="background-image: url('https://images.unsplash.com/photo-1572276596237-5db2c3e16c5d?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80')">
<h3>Wild Forest</h3>
</div>
<div class="panel" style="background-image: url('https://images.unsplash.com/photo-1507525428034-b723cf961d3e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1353&q=80')">
<h3>Sunny Beach</h3>
</div>
<div class="panel" style="background-image: url('https://images.unsplash.com/photo-1551009175-8a68da93d5f9?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1351&q=80')">
<h3>City on Winter</h3>
</div>
<div class="panel" style="background-image: url('https://images.unsplash.com/photo-1549880338-65ddcdfd017b?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80')">
<h3>Mountains - Clouds</h3>
</div>
In Style Part
.panel {
flex: 0.5; //changed 1 to 0.5;
}
.panel.active {
flex: 5;
}
.panel.active h3 {
opacity: 1;
}
Now, its look like this.
Now our template is ready, we need to implement the logic for the click event on a panel its need to expand and the rest of are shrink.
Implementing Logic
Here we write 5 hardcoded panel blocks, but in Svelte we can simplify them. For instance:
<script>
const images = [
{ src: 'https://images.unsplash.com/photo-1558979158-65a1eaa08691?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80', caption: 'Explore The World'},
{ src: 'https://images.unsplash.com/photo-1572276596237-5db2c3e16c5d?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80', caption: 'Wild Forest'},
{ src: 'https://images.unsplash.com/photo-1507525428034-b723cf961d3e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1353&q=80', caption: 'Sunny Beach'},
{ src: 'https://images.unsplash.com/photo-1551009175-8a68da93d5f9?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1351&q=80', caption: 'City on Winter'},
{ src: 'https://images.unsplash.com/photo-1549880338-65ddcdfd017b?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80', caption: 'Mountains - Clouds'}
]
</script>
<main>
<div class="container">
{#each images as {src, caption}, i}
<div class="panel {i == 0 ? 'active' : ''}" style="background-image: url({src})">
<h3>{caption}</h3>
</div>
{/each}
</div>
</main>
Here we declare an image list and we render it by each
block, each
has two arguments first one the item and the next one the index, also in the template, we render a class conditionally, so for the 0
th position add an active
class.
Our next target is we need to add a click
event and need to reference the container elements. First, let's do it in the script:
let panel_container;
function handleActiveClasses(i) {
if(panel_container){
panel_container.childNodes[i].classList.add('active')
}
}
In template for reference an element we use bind:this={panel_container}
and add attach the event handler which takes a arguments i
as an index:
<div class="container" bind:this={panel_container}>
{#each images as {src, caption}, i}
<div on:click={() => handleActiveClasses(i)} class="panel {i == 0 ? 'active' : ''}" style="background-image: url({src})">
<h3>{caption}</h3>
</div>
{/each}
</div>
Now it looks like this.
Here still has two problems, first, one is expanded only targeted panel and need to rest are shrinking, but we see every panel are expanded for click. And the second problem is the expanding panel is looking weird, so we can add a transition. first, let's add the transition:
.panel{
-webkit-transition: all 700ms ease-in;
}
.panel.active h3 {
transition: opacity 0.3s ease-in 0.4s;
}
To shrink the panel we need to remove the active
class from every element and add an active
class for the current index. Let's update our function:
function handleActiveClasses(i) {
if(panel_container){
panel_container.childNodes.forEach(panel => {
panel.classList.remove('active')
})
panel_container.childNodes[i].classList.add('active')
}
}
The final output is:
We finish our first project in Svelte.
Summary
In this project this Svelte features we used:
adding Data
styling
each
dom-events
inline-handlers
reference html elements
You can find the final code in this REPL.
GitHub profile: GitHub.
Posted on October 23, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.