Adding Tailwind and Daisy UI to SvelteKit
Tags: svelte, tailwindcss, daisyui
Published: 2022-02-18 04:53:27

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.

```bash
npm install -D tailwindcss postcss autoprefixer
```

```bash
npx tailwindcss init tailwind.config.cjs -p
```

```bash
mv postcss.config.js postcss.config.cjs
```

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

```javascript
module.exports = {
  content: ['./src/**/*.{html,js,svelte,ts}'],
  theme: {
    extend: {}
  },
  plugins: []
};
```

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
```

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

```css
@tailwind base;
@tailwind components;
@tailwind utilities;
```

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.

```javascript
// Import our global CSS
import "$lib/global.css";
```

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mt8g21dn3q95spvmnlcg.png) 

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:

```bash
npm i daisyui
```

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

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

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bqs96j3cnjus038hvwkn.png) 

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*

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

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:

```html
<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>
```

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

```javascript
import Input from "$lib/components/Input.svelte";
```

And simplify all our form code into:

```html
<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>
```

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`

```javascript
<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>
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ldulz4kx8t5c5b1aei99.png) 

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.

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

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:

```html
<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>
```

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4niqdn6fbqr64yx9w7pz.png)