DEV Community

Brewhouse Digital
Brewhouse Digital

Posted on

Adding Tailwind and Daisy UI to SvelteKit

In the second part of our series of building a fullstack site, we'll be adding in Tailwind and an amazing library that sits on top of it called Daisy UI. Tailwind has a mind-boggling level of flexibility, but sometimes you need to quickly create a site and worry about the specific design later. That's where Daisy UI comes in. Think of it like Bootstrap, but with all the goodies that comes with Tailwind. It has premade classes in place to simplify your development, so you can quickly scaffold a beautiful looking site without much effort.

Links we'll be using in this tutorial:

https://tailwindcss.com/

https://daisyui.com/

Step 1 - Install Tailwind

Even though we'll be installing Tailwind in this tutorial, we will really only be using Daisy UI for the setup.

npm install -D tailwindcss postcss autoprefixer
Enter fullscreen mode Exit fullscreen mode
npx tailwindcss init tailwind.config.cjs -p
Enter fullscreen mode Exit fullscreen mode
mv postcss.config.js postcss.config.cjs
Enter fullscreen mode Exit fullscreen mode

Now that Tailwind is installed, and our config files have been created, we can set up tailwind. Inside our tailwind.config.cjs file, add this module.exports function

module.exports = {
  content: ['./src/**/*.{html,js,svelte,ts}'],
  theme: {
    extend: {}
  },
  plugins: []
};
Enter fullscreen mode Exit fullscreen mode

This setup requires a CSS file to be imported into your main __layout.svelte file. This way all the tailwind components can be accessed in for all your pages. You can name this file anything you want, app.css, global.css, tailwind.css, just as long as it's imported into the layout file, you're good to go.

I'm going to call mine global.css and put it in the lib folder next to my store.js file.

├── source
│   ├── lib
│   │   ├── components
│   │   ├── data
│   │   ├── functions
│   │   ├── global.css
│   │   ├── store.js
│   ├── routes
│   │   ├── __layout.svelte
│   │   ├── index.svelte
│   └── app.html
Enter fullscreen mode Exit fullscreen mode

Now we import the tailwind components into that file like so:

@tailwind base;
@tailwind components;
@tailwind utilities;
Enter fullscreen mode Exit fullscreen mode

Then import it into our __layout.svelte file. If you're following along with the Backendless part of the tutorial, you can include this import anywhere you want. I'm adding mine above the Backendless import statements.

// Import our global CSS
import "$lib/global.css";
Enter fullscreen mode Exit fullscreen mode

And now we're done with Tailwind! You can test that it's working by launching the SvelteKit server npm run dev and see that all of our previous styles are now missing. Tailwind is essentially resetting absolutely everything, so we have freedom to customize the site how we want.

Image description

Let's work on Daisy UI next!

Part 2 - Daisy UI

Next on our list is to install Daisy UI and configure it with Svelte. Since Daisy UI requires Tailwind, make sure all the previous steps are completed and your site looks similar to the previous screenshot.

Load up your terminal again and run:

npm i daisyui
Enter fullscreen mode Exit fullscreen mode

Now open the tailwind.config.cjs file and in the plugins section, add in: require('daisyui') like so:

module.exports = {
  content: ['./src/**/*.{html,js,svelte,ts}'],
  theme: {
    extend: {}
  },
  plugins: [
    require('daisyui')
  ]
};
Enter fullscreen mode Exit fullscreen mode

Make sure to save, and now load up your SvelteKit server with npm run dev and see if any of your styles have changed! Your styles may look different from mine, but you can see new styles have been added to our project:

Image description

Before we go any further, I want to point out that Daisy UI has an amazing list of built-in themes. I'm going to set up the Forest theme for this site, but you can pick your whichever one you like best. You can see the full list here:

https://daisyui.com/docs/default-themes

The theme changer is in the top right corner of the page

To add a theme, you just modify the <html> tag with a data-theme attribute.

Time to test out some Daisy UI components. Let's style our form that we previously built on the __layout.svelte file. First we'll want to add the Card styles to our form, then add the base input styling, and then style up our button.

Form Tag

Let's give this tag a class of card and card-body and then a width style of 400px, like so:

p.s. this is the same HTML form from Part 1 of this series

<form on:submit={handleLogin} class="card card-body" style="max-width: 400px">
    <!-- The other html -->
</form>
Enter fullscreen mode Exit fullscreen mode

Now we'll refactor our old form fields into Daisy UI ones. The HTML is a little more verbose, so this might be a great opportunity to create a form component that we can reuse. First, go to our components folder inside of lib, and create a new component called Input.svelte. I won't go into too much detail about how Svelte components work, but this is how I structured mine:

<script>
    export let label = "";
    export let type = "";
    export let id = "";
    export let placeholder = "";
    export let value = "";

    const onInput = e => (value = e.target.value);
</script>

<div class="form-control">
    <label class="label" for={id}>
        <span class="label-text">{label}</span>
    </label>
    <input {type} {placeholder} {id} {value} on:input={onInput} class="input input-bordered">
</div>
Enter fullscreen mode Exit fullscreen mode

Now we can import our new component back into the __layout.svelte page by writing:

import Input from "$lib/components/Input.svelte";
Enter fullscreen mode Exit fullscreen mode

And simplify all our form code into:

<form on:submit={handleLogin} class="card card-body" style="max-width: 400px">
    <Input label="Email:" id="login-email" bind:value={loginData.email} type="email"/>

    <Input label="Password:" id="login-password" bind:value={loginData.password} type="password"/>

    <button type="submit" class="btn btn-primary">Log In</button>
</form>
Enter fullscreen mode Exit fullscreen mode

Much cleaner!

Organization

So far, we've been working a lot in our main Layout file. Let's move this over to its own page called login.svelte inside our routes folder. And while we're at it, let's make a register.svelte file too.

First thing we'll do inside the new Login page is to add our form and javascript code in (along with a few other classes and tags too).

login.svelte

<script>
    import {user} from "$lib/store";
    import Input from "$lib/components/Input.svelte";

    let loginData = {
        email: "",
        password: "",
    }

    async function handleLogin(e) {
        e.preventDefault();

        // Log the user in. This returns a JSON object
        let response = await Backendless.UserService.login(
            loginData.email, loginData.password, true
        );

        // Save the updated user information to our svelte store
        user.set(response);
    }
</script>

<div class="container mx-auto">
    <h1 class="text-4xl">Log In</h1>

    <form on:submit={handleLogin} class="card card-body" style="max-width: 400px">
        <Input label="Email:" id="login-email" bind:value={loginData.email} type="email"/>

        <Input label="Password:" id="login-password" bind:value={loginData.password} type="password"/>

        <button type="submit" class="btn btn-primary">Log In</button>
    </form>
</div>
Enter fullscreen mode Exit fullscreen mode

Image description

Now our code is nice and organized. We can do almost the same thing with the registration page. First create our new register.svelte, and copy and paste all the same code from the Login page into this one.

Then, update the variable and function names to be registration related (such as changing let loginData be let registerData).

Then the registration function for Backendless is a little different. We need to create a new User object. And that looks like this using our new variable names.

let user = new Backendless.User();
user.email = registerData.email;
user.password = registerData.password;
Enter fullscreen mode Exit fullscreen mode

Now, since the registration is done through Javascript, we'll need to show the user that some kind of event has occurred. You could send them to a new registration confirmation page, either to let them know the account was created or maybe that they need to check their email, or you could display a message on page. For this example, we'll just use a svelte If/Else statement to control the UI. The whole register.svelte page looks like this now:

<script>
    import Input from "$lib/components/Input.svelte";

    let pendingRegistration = true;

    let registerData = {
        email: "",
        password: "",
    }

    async function handleRegister(e) {
        e.preventDefault();

        let user = new Backendless.User();
        user.email = registerData.email;
        user.password = registerData.password;

        await Backendless.UserService.register(user)

        pendingRegistration = !pendingRegistration;
    }
</script>

<div class="container mx-auto">
    <h1 class="text-5xl font-bold">Register</h1>

    {#if pendingRegistration}
        <form on:submit={handleRegister} class="card card-body" style="max-width: 400px">
            <Input label="Email:" id="register-email" bind:value={registerData.email} type="email"/>

            <Input label="Password:" id="register-password" bind:value={registerData.password} type="password"/>

            <button type="submit" class="btn btn-primary">Register</button>
        </form>
    {:else}
        <h2 class="text-5xl font-bold">Hooray!</h2>
    {/if}
</div>
Enter fullscreen mode Exit fullscreen mode

Once the registration has completed, the pendingRegistration value is flipped so that the UI will update and hide the form. This way they don't try to submit the form again. And that's all it takes to set up a registration page.

Image description

Top comments (2)

Collapse
 
adamaslan profile image
Adam Aslan

cooooool

Collapse
 
adamaslan profile image
Adam Aslan • Edited

do you have the examples on github?