Expanding Bottom Navigation with CSS Transitions

13 November 2022

Updated: 03 September 2023

So I was looking around on YouTube and came across a video about this library called google_nav_bar for flutter and I really liked the idea of how it works and wanted to implement something similar in an app I’ve been working on

The basic functionality of the of the library can be seen on google_nav_bar package page

I thought the main challenge of this would be implementing the fade-in of the text with the expanding content section, I took a first shot with the result below:

1
<script>
2
3
let selected = 'home';
4
5
let items = ['home', 'search', 'archive', 'settings'];
6
let colors = {
7
home: 'lightpink',
8
search: 'violet',
9
archive: 'skyblue',
10
settings: 'lightgrey'
11
};
12
</script>
13
14
<svelte:head>
15
<link rel="stylesheet" href="https://unpkg.com/mono-icons@1.0.5/iconfont/icons.css" />
16
</svelte:head>
17
18
<nav class="wrapper">
19
<ul class="list">
20
{#each items as item (item)}
21
<li class="item" class:selected={selected === item} on:click={() => (selected = item)}>
22
<div class="icon" style={`--bg: ${colors[item]}`}>
23
<i class={`mi mi-${item}`} />
24
</div>
25
<div class="text">
26
{item}
27
</div>
28
</li>
29
{/each}
30
</ul>
31
</nav>
32
33
<style>
34
.mi {
35
font-size: 24px;
36
}
37
38
.wrapper {
39
display: flex;
40
width: 100%;
41
}
42
43
.list {
44
flex: 1;
45
display: flex;
46
flex-direction: row;
47
align-items: center;
48
justify-content: space-between;
49
padding: 10px 20px;
50
}
51
52
.item {
53
display: flex;
54
flex-direction: row;
55
align-items: center;
56
gap: 8px;
57
justify-content: flex-start;
58
}
59
60
.item .text {
61
width: 0px;
62
opacity: 0;
63
overflow: hidden;
64
transition: width 0.15s 0s, opacity 0.15s 0s;
65
}
66
67
.item.selected .text {
68
width: 100px;
69
opacity: 1;
70
transition: width 0.15s 0s, opacity 0.15s 0.075s;
71
}
72
73
.icon {
74
display: flex;
75
align-items: center;
76
justify-content: center;
77
color: var(--bg);
78
line-height: 0;
79
}
80
81
/* resets */
82
ul {
83
padding: 0;
84
margin: 0;
85
}
86
87
li {
88
margin: 0;
89
list-style: none;
90
}
91
</style>

I like the overall feel and I think the finicky bits of using the transition are done, but I’d still like to play around a bit more to see how close to the original library I can get it

For now though, here’s the REPL with the current working state of the component: