Back

Creating a Sidebar Menu Layout with SvelteKit

Creating a Sidebar Menu Layout with SvelteKit

In this article, we are going to create a responsive sidebar menu layout using SvelteKit 1.0.0 and Flowbite-Svelte. You can find the demo at https://flowbite-sveltekit-responsive-sidebar-layout.vercel.app/. Flowbite-Svelte is an official Flowbite UI component library for Svelte. It has more than 50 UI components, and you can build websites faster.

Let’s get started.

Installing all packages

We are going to create a new SvelteKit app:

npm create svelte@latest responsive-sidebar-layout
cd responsive-sidebar-layout
npm i

1

Tailwind CSS is a utility-first CSS framework. You can add it directly to your markup. Let’s install Tailwind CSS:

npx svelte-add@latest tailwindcss
npm i

Update tailwind.config.cjs:

const config = {
  content: [
    "./src/**/*.{html,js,svelte,ts}",
    "./node_modules/flowbite-svelte/**/*.{html,js,svelte,ts}",
  ],
  theme: {
    extend: {},
  },
  plugins: [
    require('flowbite/plugin')
  ],
  darkMode: 'class',
};
module.exports = config;

Installing Flowbite, Flowbite-Svelte, and dependencies:

npm i -D flowbite flowbite-svelte classnames @popperjs/core 

At the time of writing this, you may need to use esbuild@0.16.8:

npm i -D esbuild@0.16.8

Start the server and check if it works without any errors:

npm run dev

You should see the following at http://127.0.0.1:5173/.

2

We will use Svelte-Heros SVG icons for menu icons and our logo. Let’s install it:

npm i -D svelte-heros-v2

Here we installed Hero icons version 2 with Svelte-Heros-v2.

Creating dummy pages

We need some dummy pages. Create src/routes/pages/about/+page.svelte, src/routes/blog/2022-01-01/+page.svelte, and src/routes/blog/2022-01-2/+page.svelte.

Instead of creating separate directories for each page, you can use a script to add multiple files to a directory at once. This can save time and effort, especially if you have many pages. I will demonstrate this method in a future article, so stay tuned!

3

You can add any content for each article. Now you can visit http://127.0.0.1:5173/pages/about, http://127.0.0.1:5173/blog/2023-01-01, and http://127.0.0.1:5173/blog/2023-01-02.

4

Importing components and utilities

Let’s import various components from the Flowbite-Svelte library and some additional utilities such as Cog from svelte-heros-v2 and the page from SvelteKit, onMount, and sinIn easing function from Svelte.

<script lang="ts">
  import '../app.postcss';
  import { page } from '$app/stores';
  import { onMount } from 'svelte';
  import {
    Navbar,
    NavBrand,
    NavLi,
    NavUl,
    NavHamburger,
    Sidebar,
    SidebarGroup,
    SidebarItem,
    SidebarWrapper,
    Drawer,
    CloseButton,
    SidebarDropdownWrapper
  } from 'flowbite-svelte';
  import { Cog } from 'svelte-heros-v2';
  import { sineIn } from 'svelte/easing';
</script>
  • Line 3: The SvelteKit $page store is imported, which allows the current page, parameters, current route, and status to be accessed.
  • Line 4: Svelte [onMount](https://svelte.dev/docs#run-time-svelte-onmount) run as soon as the component has been mounted to the DOM. We are going to use it to check the screen width.
  • Lines 5-18: Various Flowbite-Svelte components, including Navbar, Drawer, and Sidebar, are imported for use in the code.
  • Line 19: An icon is imported for use in the NavBrand component.
  • Line 20: The Svelte sineIn easing function is imported.

The top navigation bar consists of a hamburger menu for the Drawer and a full menu for larger screens. The NavUl and NavLi components are used to construct the main navigation.

<script lang="ts">
  // Append the following
  // Navigation component
  let drawerHidden: boolean = false;
  const toggleDrawer = () => {
    drawerHidden = !drawerHidden;
  };
  let divClass = 'w-full md:block md:w-auto pr-8';
  let ulClass = 'flex flex-col p-4 mt-4 md:flex-row md:space-x-8 md:mt-0 md:text-lg md:font-medium';
</script>

<Navbar let:hidden let:toggle>
  <NavHamburger on:click={toggleDrawer} btnClass="ml-3 lg:hidden" />
  <NavBrand href="/" class="lg:ml-64">
    <Cog />
    <span class= "self-center whitespace-nowrap text-xl font-semibold dark:text-white pl-4">
      My Website
    </span>
  </NavBrand>
  <NavHamburger on:click={toggle} />
  <NavUl {hidden} {divClass} {ulClass}>
    <NavLi href="/">Home</NavLi>
    <NavLi href="/pages/about">About</NavLi>
    <NavLi href="https://github.com/shinokada/flowbite-sveltekit-responsive-sidebar-layout"
      >GitHub</NavLi
    >
  </NavUl>
</Navbar>

<div class="flex px-4 mx-auto w-full">
  <main class="lg:ml-72 w-full mx-auto">
    <slot />
  </main>
</div>
  • Lines 4-7: The toggleDrawer function shows the Drawer component when the hamburger menu is clicked.
  • Lines 8-9: Styling for the component.
  • Line 12-29: The Navbar component is added to the code, with let:hidden and let:toggle directives. These prop values can be used in child components. The hidden prop is used with the NavUl component, and the toggle prop is used with the NavHamburger component.
  • Line 13: The hamburger menu is hidden on screens larger than 1024px and has a click event (toggleDrawer) that allows it to show the Drawer component.
  • Lines 14-19: The NavBrand component is added, using the imported icon as the logo.
  • Line 20: The hamburger menu for screens smaller than 768px is added, with the toggle prop for the click event.
  • Lines 21-27: The NavUl and NavLi components are used to construct the main navigation.
  • Line 30-34: Adding styling to the main content.

Screen size larger than 769px: 5

Screen size less than 768 px: 6

Opening the main navigation when the screen size is less than 768px: 7

Currently, the left hamburger menu doesn’t do anything. In the next section, we are going to add the Drawer component.

Session Replay for Developers

Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — an open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.

Drawer component

<script lang="ts">
  // Append the following
  // Drawer component
  let backdrop: boolean = false;
  let activateClickOutside = true;
  let breakPoint: number = 1024;
  let width: number;
  let transitionParams = {
    x: -320,
    duration: 200,
    easing: sineIn
  };
  $: if (width >= breakPoint) {
    drawerHidden = false;
    activateClickOutside = false;
  } else {
    drawerHidden = true;
    activateClickOutside = true;
  }
  onMount(() => {
    if (width >= breakPoint) {
      drawerHidden = false;
      activateClickOutside = false;
    } else {
      drawerHidden = true;
      activateClickOutside = true;
    }
  });
</script>

<svelte:window bind:innerWidth={width} />
<!-- After Navbar -->
<Drawer
  transitionType= "fly"
  {backdrop}
  {transitionParams}
  bind:hidden={drawerHidden}
  bind:activateClickOutside
  width="w-64"
  class="overflow-scroll pb-32"
  id= "sidebar"
>
  Drawer
</Drawer>
  • Line 4: The backdrop for the Drawer component is set to false. The default value is true, so if you want to show the backdrop, remove it or set it to true.
  • Line 5: The activateClickOutside prop is set to true, allowing the Drawer component to be closed by clicking outside its area.
  • Line 6: The breakpoint for the screen size is set to 1024px.
  • Line 7: A width variable is created to store the screen width.
  • Line 8-12: Transition parameters are set.
  • Line 13-19: The drawerHidden and activateClickOutside props are controlled based on the screen size. If the screen size is less than the breakpoint (1024px), they are set to false; otherwise, they are set to true.
  • Line 20-28: The same actions are performed on the component mount, checking the screen size at that time.
  • Line 31: The <svelte:window> element is used to add event listeners for changes in the window size, and the innerWidth is bound to the width variable.
  • Line 33-44: We add the Drawer component using the transitionType property to “fly” and pass values to the backdrop and transitionParams properties. We also bind the hidden property to a value drawerHidden and set the activateClickOutside property. The width property is set to w-64.

Make the screen size less than 1024px and click the hamburger menu to see the Drawer component in action.

8

In the next section, we will add the Sidebar Component within the Drawer component.

<script lang="ts">
// Append the following
// Sidebar Component
const toggleSide = () => {
  if (width < breakPoint) {
    drawerHidden = !drawerHidden;
  }
};
$: activeUrl = $page.url.pathname;
let spanClass = 'pl-2 self-center text-md text-gray-900 whitespace-nowrap dark:text-white';
</script> 

<!-- Add the following within the Drawer component -->
<div class=" flex items-center">
  <CloseButton on:click={() => (drawerHidden = true)} class="mb-4 dark:text-white lg:hidden" />
</div>
<Sidebar asideClass="w-54">
  <SidebarWrapper divClass="overflow-y-auto py-4 px-3 rounded dark:bg-gray-800">
    <SidebarGroup>
      <SidebarItem label="Home" href="/" on:click={toggleSide} active={activeUrl === `/`} />
      <SidebarItem
        label= "About"
        href="/pages/about"
        {spanClass}
        on:click={toggleSide}
        active={activeUrl === '/pages/about'}
      />
      <SidebarDropdownWrapper label="Articles">
        <SidebarItem
          label= "Article 1"
          href={`/blog/2023-01-01`}
          {spanClass}
          on:click={toggleSide}
          active={activeUrl === '/blog/2023-01-01'}
        />
        <SidebarItem
          label= "Article 2"
          href="/blog/2023-01-02"
          {spanClass}
          on:click={toggleSide}
          active={activeUrl === '/blog/2023-01-02'}
        />
      </SidebarDropdownWrapper>
    </SidebarGroup>
  </SidebarWrapper>
</Sidebar>
  • Line 4-8: toggleSide is a function that toggles the value of drawerHidden if the screen’s width is less than the breakPoint value.
  • Line 9: activeUrl is a reactive variable set to the current page’s URL pathname.
  • Line 10: spanClass contains a class for styling a SidebarItem components.

Check it on your localhost:

npm run dev

9

Adding icons to sidebar items

You can enhance the appearance and usability of your sidebar menu by adding icons to its items. For instance, you can add a home icon next to the ‘Home’ menu item to make it more visually appealing and easier to identify for users.

<script>
import { Home } from 'svelte-heros-v2'
</script>

<SidebarItem label="Home" href="/" on:click={toggleSide} active={activeUrl === `/`}>
  <svelte:fragment slot="icon">
    <Home />
  </svelte:fragment>
<SidebarItem />

Remember to include the necessary import statement at the top of your script tag: import { Home } from 'svelte-heros-v2". Then, you can use the icon` slot to add your icon component within the menu item. This will ensure that the icon is displayed properly in your sidebar menu.

Conclusion

This tutorial provided in this article demonstrates how to use SvelteKit and Flowbite-Svelte to create a responsive sidebar menu layout for a website. These tools allow for the creation of a professional-looking menu with minimal effort and time. By following the steps outlined in the tutorial, you can easily set up and customize your own responsive sidebar menu layout using SvelteKit and Flowbite-Svelte. There may be additional tasks to complete before your site is fully functional, but many of them can be efficiently addressed by utilizing the Flowbite-Svelte components. These components provide pre-built, customizable elements that can save time and simplify development.

Additional details can be found in the repository and demo at https://sveltekit-sidebar-layout.vercel.app/.

A TIP FROM THE EDITOR: If you are interested in Svelte, don’t miss Exploring SvelteKit In 2022 By Building A Portfolio Website.

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs and track user frustrations. Get complete visibility into your frontend with OpenReplay, the most advanced open-source session replay tool for developers.

OpenReplay