We build a login using TailwindCSS

Published on January 28th, 2018

In this episode, we are gonna build a login using TailwindCSS. I have already prepared the login in Sketch so that we have a good template to work from. This is what we want to build for this episode.

Lets get started.

Cleaning up our packages.json

Before starting I like to clean my environment. For now, that means removing the items jQuery and bootstrap-sass from the package.json file since we won't be using them in this project.

After we have removed those packages, we can add TailwindCSS as a dependency. You can either add it directly in the package.json file and install it, or you pull it in via the command line. Either way is fine, however I suggest you at least specify a specific version of TailwindCSS. At the time of writing, the latest version is 0.4 so we'll be using that.

Our file should now look like

package.json
{
    "private": true,
    "scripts": {
        "dev": "npm run development",
        "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
        "watch": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
        "watch-poll": "npm run watch -- --watch-poll",
        "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
        "prod": "npm run production",
        "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
    },
    "devDependencies": {
        "axios": "^0.17",
        "cross-env": "^5.1",
        "laravel-mix": "^1.0",
        "less": "^2.7.3",
        "less-loader": "^4.0.5",
        "lodash": "^4.17.4",
        "tailwindcss": "^0.4",
        "vue": "^2.5.7"
    }
}

Now it's time to install these packages, lets give it a shot on the command line with

$ yarn install

Cool! All required packages are installed.

Time to get TailwindCSS running

TailwindCSS gets configured by a tailwind.js file. We don't yet have that file so we should generate it. Head over to the console and run:

$ tailwind init

Now we can see a tailwind.js file created in our application root. We are also using Laravel Mix, and therefore need to configure that properly too. Open up the webpack.mix.js file and replace its contents with the following.

webpack.mix.js
let mix = require('laravel-mix');
let tailwindcss = require('tailwindcss');

mix
    .js('resources/assets/js/app.js', 'public/js')
    .less('resources/assets/less/app.less', 'public/css')
    .options({
        postCss: [
            tailwindcss('tailwind.js'),
        ]
    })
;

if (mix.inProduction()) {
    mix.version();
}

What have we done there? Let's go through it really quick. We pull in TailwindCSS and assign it to a variable called tailwindcss for use later on. It compiles our resources/assets/js/app.js file down and saves it to the public/js directory. Instead of using SASS, we are using LESS; that's why we have replaced the sass method with less. It's basically the same as the js-method, it grabs our app.less and compiles it down to a single app.css file and saves it to the public/css directory. We have used postCSS as an option and have called tailwindcsswith our tailwind.js configuration. PostCSS will walk over our CSS from the less compilation and compile it again, but this time through TailwindCSS. Finally, in a production build, we want Laravel Mix to add some version tags to our compiled assets for caching and performance reasons.

Now it's time to run yarn run dev.

Laravel Mix noticed that we are using some dependencies that we have not specified in the package.json file, and it has installed them for us. Don't believe me? Take a look at the package.json file; there will be two more packages now, less and less-loader have been added as dependencies.

Resolving the final issue

There are still some smaller issues that we have to solve.

You will have noticed that yarn run dev currently has an error. This is because it is trying to compile our app.less file, but that file doesn't exist yet.

So, create an empty app.less file in the resources/assets/less directory.

$ mkdir resources/assets/less
$ touch resources/assets/less/app.less

After that remove the sass directory and files as we won't be using sass in this project.

$ rm -Rf resources/assets/sass

If you try to run yarn run dev again there might be a different error.

If you didn't remove your node_modules directory and reinstall everything from scratch after we modified the package.json file, then you might have to do that now. Simply rm -rf node_modules && yarn install and you should be fine. If you didn't get an error then you can ignore this section.

In our resources/assets/js/bootstrap.js file we currently reference both jQuery and Bootstrap. Since we won't be using them, you can those that part, so that you end up with a file that looks like:

resources/assets/js/bootstrap.js
window._ = require('lodash');

/**
 * We'll load the axios HTTP library which allows us to easily issue requests
 * to our Laravel back-end. This library automatically handles sending the
 * CSRF token as a header based on the value of the "XSRF" token cookie.
 */

window.axios = require('axios');

window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';

/**
 * Next we will register the CSRF Token as a common header with Axios so that
 * all outgoing HTTP requests automatically have it attached. This is just
 * a simple convenience so we don't have to attach every token manually.
 */

let token = document.head.querySelector('meta[name="csrf-token"]');

if (token) {
    window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
} else {
    console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token');
}

/**
 * Echo exposes an expressive API for subscribing to channels and listening
 * for events that are broadcast by Laravel. Echo and event broadcasting
 * allows your team to easily build robust real-time web applications.
 */

// import Echo from 'laravel-echo'

// window.Pusher = require('pusher-js');

// window.Echo = new Echo({
//     broadcaster: 'pusher',
//     key: 'your-pusher-key',
//     cluster: 'mt1',
//     encrypted: true
// });

If you run yarn run dev again it should now run without any issues. If you take a look in our compiled css file public/css/app.css now you should see... nothing! Yeah! That's because our app.less is still empty.

Now we can add the tailwind configuration where all the magic happens. Go to your resources/assets/less/app.less and paste this in. By the way, you can find this basic example in the TailwindCSS Documentation.

resources/assets/less/app.less
/**
 * This injects Tailwind's base styles, which is a combination of
 * Normalize.css and some additional base styles.
 *
 * You can see the styles here:
 * https://github.com/tailwindcss/tailwindcss/blob/master/css/preflight.css
 *
 * If using `postcss-import`, you should import this line from it's own file:
 *
 * @import "./tailwind-preflight.css";
 *
 * See: https://github.com/tailwindcss/tailwindcss/issues/53#issuecomment-341413622
 */
@tailwind preflight;

/**
 * Here you would add any of your custom component classes; stuff that you'd
 * want loaded *before* the utilities so that the utilities could still
 * override them.
 *
 * Example:
 *
 * .btn { ... }
 * .form-input { ... }
 *
 * Or if using a preprocessor or `postcss-import`:
 *
 * @import "components/buttons";
 * @import "components/forms";
 */

/**
 * ...
 */

/**
 * This injects all of Tailwind's utility classes, generated based on your
 * config file.
 *
 * If using `postcss-import`, you should import this line from it's own file:
 *
 * @import "./tailwind-utilities.css";
 *
 * See: https://github.com/tailwindcss/tailwindcss/issues/53#issuecomment-341413622
 */
@tailwind utilities;

/**
 * Here you would add any custom utilities you need that don't come out of the
 * box with Tailwind.
 *
 * Example :
 *
 * .bg-pattern-graph-paper { ... }
 * .skew-45 { ... }
 *
 * Or if using a preprocessor or `postcss-import`:
 *
 * @import "utilities/background-patterns";
 * @import "utilities/skew-transforms";
 */

A new yarn run dev and here we go. A brand new css file using TailwindCSS, waiting to be used.

Color configuration

How I usually work is by picking a default grey color. From there, I will choose four darker greys (towards black), and four lighter greys (towards white). With that, I have a nice grey color palette which will cover 99% of the greys I need. I will then add my primary brand color, and a secondary brand color that is a darker version of the primary color. The darker color is mostly used for hover effects.

That's it. No more colors for now.

This is important: Start with one brand color, in this case our primary one. Don't add colors until you need them.

Our tailwind.js should look like this in the colors section:

tailwind.js
let colors = {
  'transparent': 'transparent',

  'black': '#2B4964',
  'grey-darkest': '#626471',
  'grey-darker': '#878c98',
  'grey-dark': '#adb4c2',
  'grey': '#d5d9e3',
  'grey-light': '#dee1e8',
  'grey-lighter': '#eaebef',
  'grey-lightest': '#fcfcfc',
  'white': '#ffffff',

  'primary': '#2b79c1',
  'primary-dark': '#266299'
}

The basic HTML and basic styling

Now for some HTML, clear out the default content from resources/views/welcome.blade.php, we'll be using that file for now to sketch out a first draft. Later on we'll create a dedicated file for it and clean this up. But for now it's okay.

resources/vierws/welcome.blade.php
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="csrf-token" content="{{ csrf_token() }}">

    <title>Login</title>

    <link href="https://fonts.googleapis.com/css?family=Lato:300,400,700" rel="stylesheet">
    <link href="{{ mix('/css/app.css') }}" rel="stylesheet">
</head>
<body class="bg-grey-lighter text-base text-grey-darkest font-normal relative">
    <div class="h-2 bg-primary"></div>

    <div class="container mx-auto p-8">
        <div class="mx-auto max-w-sm">
            <div class="py-10 text-center">
                @include('logo', ['style' => 'max-width: 12rem;'])
            </div>

            <div class="bg-white rounded shadow">
                <div class="border-b py-8 font-bold text-black text-center text-xl tracking-widest uppercase">
                    Welcome back!
                </div>

                <form class="bg-grey-lightest px-10 py-10">
                    {{ csrf_field() }}

                    <div class="mb-3">
                        <input class="border w-full p-3" name="email" type="text" placeholder="E-Mail">
                    </div>
                    <div class="mb-6">
                        <input class="border w-full p-3" name="password" type="password" placeholder="**************">
                    </div>
                    <div class="flex">
                        <button class="bg-primary hover:bg-primary-dark w-full p-4 text-sm text-white uppercase font-bold tracking-wider">
                            Login
                        </button>
                    </div>
                </form>

                <div class="border-t px-10 py-6">
                    <div class="flex justify-between">
                        <a href="#" class="font-bold text-primary hover:text-primary-dark no-underline">Don't have an account?</a>
                        <a href="#" class="text-grey-darkest hover:text-black no-underline">Forgot Password?</a>
                    </div>
                </div>
            </div>
        </div>
    </div>
</body>
</html>

Nothing fancy here. A basic HTML5 document with some minor modifications. We add the csrf-token meta-tag to help protect against CSRF (Cross-Site Request Forgery) attacks. It's not important right now to understand what that tag does, we'll cover that later. For our design, we need a font called "Lato", which we get from Google Fonts. We are also including the CSS file that Laravel Mix has generated for us.

It is important that we cover some TailwindCSS basics.

When you add any custom CSS to your LESS file, it's important that we add it after the tailwind preflight code, but before the tailwind utilities. The tailwind utilities should always be at the bottom of the file so that they can override any other attributes if necessary.

resources/assets/less/app.less
/**
 * This injects Tailwind's base styles, which is a combination of
 * Normalize.css and some additional base styles.
 *
 * You can see the styles here:
 * https://github.com/tailwindcss/tailwindcss/blob/master/css/preflight.css
 *
 * If using `postcss-import`, you should import this line from it's own file:
 *
 * @import "./tailwind-preflight.css";
 *
 * See: https://github.com/tailwindcss/tailwindcss/issues/53#issuecomment-341413622
 */
@tailwind preflight;

/**
 * Here you would add any of your custom component classes; stuff that you'd
 * want loaded *before* the utilities so that the utilities could still
 * override them.
 *
 * Example:
 *
 * .btn { ... }
 * .form-input { ... }
 *
 * Or if using a preprocessor or `postcss-import`:
 *
 * @import "components/buttons";
 * @import "components/forms";
 */

html {
    -moz-osx-font-smoothing: grayscale;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;

    @apply .font-sans;
    @apply .leading-normal;
    @apply .text-grey-darkest;
}

/**
 * This injects all of Tailwind's utility classes, generated based on your
 * config file.
 *
 * If using `postcss-import`, you should import this line from it's own file:
 *
 * @import "./tailwind-utilities.css";
 *
 * See: https://github.com/tailwindcss/tailwindcss/issues/53#issuecomment-341413622
 */
@tailwind utilities;

/**
 * Here you would add any custom utilities you need that don't come out of the
 * box with Tailwind.
 *
 * Example :
 *
 * .bg-pattern-graph-paper { ... }
 * .skew-45 { ... }
 *
 * Or if using a preprocessor or `postcss-import`:
 *
 * @import "utilities/background-patterns";
 * @import "utilities/skew-transforms";
 */

We have added some basic CSS here to improve font rendering and readability, and @apply-ed some tailwind css classes. This will set our default font for the website, some leading and the default text color. What we haven't defined yet though is that we would like to use "Lato" as the default sans-serif font.

To do that, add Lato to the fonts stack in the tailwind.js file. While we are editing the tailwind.js, we should also make some changes that I know we will need later on.

Add a new padding of 10 with a value of 2.5rem to the padding section. Additionally, we want to change the tracking (letter spacing) a little bit. We will change the wide tracking value to 0.03em and add two more trackings: wider and widest, which we will give values of 0.06em and 0.1emrespectively.

Here is what we now have:

tailwind.js
let colors = {
  'transparent': 'transparent',

  'black': '#2B4964',
  'grey-darkest': '#626471',
  'grey-darker': '#878c98',
  'grey-dark': '#adb4c2',
  'grey': '#d5d9e3',
  fonts: {
    'sans': [
      'Lato',
//...
    ],
//...
  },
//...
  tracking: {
    'tight': '-0.05em',
    'normal': '0',
    'wide': '0.03em',
    'wider': '0.06em',
    'widest': '0.1em',
  },
//...
  padding: {
    'px': '1px',
    '0': '0',
    '1': '0.25rem',
    '2': '0.5rem',
    '3': '0.75rem',
    '4': '1rem',
    '6': '1.5rem',
    '8': '2rem',
    '10': '2.5rem',
  },
}

Creating the Login

Now we have the setup complete, we can start styling the login page.

I am not really sure how I should show you the progress, because if I show you each line we'll still not be done in the next year. Therefore, I think it is best that I show you the final file, and i'll explain the parts where I think it is necessary to. Most of what I don't explain will just be applying default tailwind classes to HTML, and I hope that you're familiar enough with HTML that it's not necessary to explain that as well.

So, here is what we have got so far.

I have left out the logo for now, because it is something that I would like to explain a little bit more.

resources/views/welcome.blade.php
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="csrf-token" content="{{ csrf_token() }}">

    <title>Login</title>

    <link href="https://fonts.googleapis.com/css?family=Lato:300,400,700" rel="stylesheet">
    <link href="{{ mix('/css/app.css') }}" rel="stylesheet">
</head>
<body class="bg-grey-lighter text-base text-grey-darkest font-normal relative">
    <div class="h-2 bg-primary"></div>

    <div class="container mx-auto p-8">
        <div class="mx-auto max-w-sm">

            <!-- ... -->

            <div class="py-10 text-center">
                @include('logo', ['style' => 'max-width: 12rem;'])
            </div>

            <div class="bg-white rounded shadow">
                <div class="border-b py-8 font-bold text-black text-center text-xl tracking-widest uppercase">
                    Welcome back!
                </div>

                <form class="bg-grey-lightest px-10 py-10">
                    {{ csrf_field() }}

                    <div class="mb-3">
                        <input class="border w-full p-3" name="email" type="text" placeholder="E-Mail">
                    </div>
                    <div class="mb-6">
                        <input class="border w-full p-3" name="password" type="password" placeholder="**************">
                    </div>
                    <div class="flex">
                        <button class="bg-primary hover:bg-primary-dark w-full p-4 text-sm text-white uppercase font-bold tracking-wider">
                            Login
                        </button>
                    </div>
                </form>

                <div class="border-t px-10 py-6">
                    <div class="flex justify-between">
                        <a href="#" class="font-bold text-primary hover:text-primary-dark no-underline">Don't have an account?</a>
                        <a href="#" class="text-grey-darkest hover:text-black no-underline">Forgot Password?</a>
                    </div>
                </div>
            </div>
        </div>
    </div>
</body>
</html>

The logo is still missing

The only thing left to do now is the logo, so let's work on that.

You might be thinking "why not just save the logo as a png or svg and reference it with an imgtag" and, while we certainly could do that, I prefer to do it a different way that will give us a lot more flexibility. We will be using an svg, however, we will save it as a blade template called logo.blade.phpinside the resources/views directory. With the logo being a blade template we can now use the blade syntax inside of the image, and control it however we like.

Create a file called logo.blade.php in resources/views and put in the following content:

resources/views/logo.blade.php
<svg class="{{ $class ?? '' }}" style="{{ $style ?? '' }}" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1057 298">
    <g fill="none" fill-rule="evenodd">
        <g fill="#2b79c1">
            <path d="M119 213.62447v-74.24894C119 132.5389 113.4005 127 106.49823 127 99.59523 127 94 132.5389 94 139.37553v74.24894C94 220.4611 99.59523 226 106.49823 226 113.4005 226 119 220.4611 119 213.62447m38-.9564v-47.33684C157 158.51868 151.4043 153 144.4993 153 137.5957 153 132 158.5187 132 165.33123v47.33684C132 219.4806 137.5957 225 144.4993 225c6.905 0 12.5007-5.5194 12.5007-12.33193"/>
            <path d="M118.50105 0c-32.6831-.00772-62.3875 13.33825-83.79115 34.85872C13.2832 56.35744-.0056 86.19072 0 119.01792c-.0056 22.57904 6.29005 43.78433 17.2012 61.7844 9.6133 15.86325 22.80212 29.26888 38.45736 39.1183v65.7211C55.65856 292.4656 61.16864 298 67.964 298c6.79534 0 12.30333-5.53438 12.30333-12.3583V106.3964c0-6.8267-5.508-12.35688-12.30334-12.35688-6.79537 0-12.30545 5.53017-12.30545 12.35688v82.61835c-6.7674-6.13316-12.67445-13.20486-17.43253-21.06068-8.64392-14.27748-13.61376-30.97328-13.61586-48.93614.0056-26.0784 10.4897-49.57493 27.5001-66.67928 17.02996-17.0861 40.42685-27.61573 66.39078-27.62345 25.96532.00772 49.35942 10.53736 66.38868 27.62345 17.0104 17.10435 27.4945 40.6009 27.5015 66.6793-.0035 15.49962-3.70135 30.04175-10.26187 42.9195-6.55982 12.8665-15.9991 24.04548-27.44978 32.6482-5.4423 4.0932-6.55143 11.8346-2.48177 17.3016 4.07177 5.46347 11.78546 6.58172 17.22566 2.492 14.43636-10.85324 26.32036-24.91873 34.60925-41.1772 8.291-16.24933 12.9687-34.7134 12.9673-54.1841.0056-32.8272-13.2832-62.66048-34.7078-84.1592C180.88787 13.33825 151.18346-.00772 118.50106 0z"/>
        </g>
        <path fill="#2b4964" d="M295.20898 68.09766v62.73046h19.92383c4.27413 0 8.3016-.82193 12.08254-2.46582 3.78095-1.64388 7.10155-3.87954 9.96192-6.70703 2.86036-2.82748 5.1289-6.1481 6.80566-9.9619 1.67678-3.81383 2.51515-7.8906 2.51515-12.23048 0-4.40564-.83837-8.5153-2.51514-12.3291-1.67676-3.81384-3.9453-7.13445-6.80565-9.96193-2.86037-2.8275-6.1974-5.0467-10.01123-6.65772-3.81383-1.611-7.82485-2.4165-12.0332-2.4165H295.209zm-20.91015 126.44726V57.64258c0-1.44662.26302-2.81103.78906-4.09326.52603-1.28224 1.26576-2.40006 2.21922-3.35352.95345-.95345 2.05484-1.6932 3.3042-2.21924 1.24935-.52604 2.6302-.78906 4.14258-.78906h30.3789c4.7344 0 9.3208.62467 13.7593 1.87402 4.4385 1.24936 8.59746 3.02473 12.47704 5.32618 3.87958 2.30144 7.43032 5.0467 10.65234 8.23584 3.22203 3.18914 5.96728 6.72345 8.23584 10.60302 2.26857 3.87958 4.04394 8.03855 5.32618 12.47705 1.28223 4.4385 1.92334 9.0249 1.92334 13.7593 0 14.3347-5.16174 26.6637-15.48536 36.9873-10.1921 10.1921-22.4882 15.2881-36.88867 15.2881H295.209v42.80663c0 2.89325-1.0192 5.35904-3.0576 7.39746-2.03846 2.0384-4.50426 3.0576-7.3975 3.0576-2.89324 0-5.35903-1.0192-7.39745-3.05762-2.03843-2.03842-3.05762-4.5042-3.05762-7.39746zm135.02832-119.6416c0 3.35353-1.18358 6.21386-3.55078 8.58106-2.3672 2.3672-5.22753 3.55078-8.58106 3.55078-3.3535 0-6.21383-1.1836-8.58103-3.5508-2.3672-2.36718-3.55078-5.2275-3.55078-8.58104 0-3.35353 1.18357-6.21385 3.55077-8.58105 2.3672-2.3672 5.22752-3.5508 8.58105-3.5508 3.35354 0 6.21387 1.1836 8.58107 3.5508 2.3672 2.3672 3.55077 5.22752 3.55077 8.58105zM386.9375 194.64355V104.8877c0-2.89325 1.00276-5.3426 3.0083-7.34815 2.00554-2.00554 4.42202-3.0083 7.2495-3.0083 2.8275 0 5.24398 1.00276 7.24952 3.0083 2.00555 2.00554 3.04118 4.4549 3.10694 7.34814v89.75584c-.06576 2.89325-1.1014 5.3426-3.10694 7.34815-2.00554 2.00553-4.42202 3.0083-7.2495 3.0083-2.8275 0-5.24397-1.00277-7.24952-3.0083-2.00554-2.00556-3.0083-4.4549-3.0083-7.34816zm62.33594-89.95312c8.74548-6.77282 19.03607-10.15918 30.87207-10.15918 6.90435 0 13.46337 1.34797 19.67726 4.04395 6.2139 2.69597 11.68797 6.3618 16.42237 10.99755 4.7344 4.63577 8.4824 10.0934 11.24414 16.37305 2.76173 6.27966 4.14258 12.97018 4.14258 20.07178v48.62597c0 2.89325-1.00276 5.3426-3.0083 7.34815C526.61798 203.99724 524.2015 205 521.374 205c-2.89324 0-5.3426-1.00276-7.34814-3.0083-2.00554-2.00555-3.0083-4.4549-3.0083-7.34815V146.0176c0-4.20836-.82193-8.1865-2.46582-11.93457-1.6439-3.74806-3.8631-7.01935-6.65772-9.81396-2.7946-2.7946-6.0659-5.01382-9.81396-6.6577-3.74807-1.6439-7.72622-2.46583-11.93457-2.46583-4.2741 0-8.2687.8055-11.9839 2.4165-3.7152 1.61102-6.98647 3.83024-9.81395 6.65773-2.8275 2.82748-5.0467 6.1152-6.65772 9.86328-1.611 3.74807-2.4165 7.72622-2.4165 11.93458v48.62597c0 2.89325-1.00276 5.3426-3.0083 7.34815-2.00555 2.00554-4.42203 3.0083-7.2495 3.0083-2.89326 0-5.34262-1.00276-7.34816-3.0083-2.00554-2.00555-3.0083-4.4549-3.0083-7.34815v-89.7559c0-2.8275 1.00276-5.2604 3.0083-7.29883 2.00554-2.03842 4.4549-3.05762 7.34814-3.05762 2.8275 0 5.24398 1.0192 7.24953 3.05762 2.00554 2.03842 3.0083 4.40558 3.0083 7.10156zm153.07812 10.45508c-4.8659 0-9.40297.92058-13.61133 2.76174-4.20835 1.84115-7.85773 4.3234-10.94824 7.44677-3.09053 3.1234-5.5399 6.7892-7.34816 10.99757-1.80828 4.20836-2.7124 8.67967-2.7124 13.41406 0 4.7344.90412 9.2057 2.7124 13.41407 1.80827 4.20834 4.25763 7.87416 7.34814 10.99755 3.0905 3.12338 6.73988 5.60562 10.94823 7.44677 4.20837 1.84116 8.74543 2.76172 13.61134 2.76172 4.80016 0 9.30434-.92056 13.5127-2.76172 4.20835-1.84115 7.87417-4.33982 10.99756-7.4961 3.12338-3.15626 5.58918-6.82207 7.39746-10.99755 1.80827-4.17548 2.7124-8.63035 2.7124-13.36474 0-4.7344-.90413-9.18927-2.7124-13.36475-1.80828-4.17548-4.27408-7.8413-7.39746-10.99756-3.1234-3.15626-6.7892-5.65494-10.99756-7.4961-4.20836-1.84115-8.71254-2.7617-13.5127-2.7617zm34.62012 77.72267C627.10835 200.9561 615.56843 205 602.35156 205c-15.25528 0-28.27468-5.39187-39.0586-16.17578-10.7839-10.7839-16.17577-23.8033-16.17577-39.0586 0-15.25528 5.39185-28.27468 16.17576-39.0586 10.7839-10.7839 23.8033-16.17577 39.0586-16.17577 15.12377 0 28.14317 5.39187 39.0586 16.17578 10.7839 10.7839 16.17577 23.8033 16.17577 39.0586v54.83984c0 4.7344-.7233 9.2057-2.16992 13.41406-1.44662 4.20836-3.45213 8.07144-6.0166 11.58936-2.56446 3.5179-5.58917 6.69055-9.0742 9.51804-3.48506 2.8275-7.2495 5.2111-11.29347 7.15088-4.04397 1.9398-8.2687 3.4357-12.67432 4.4878-4.4056 1.05208-8.81116 1.57812-13.2168 1.57812-5.26043 0-10.42216-.67398-15.48534-2.02197-5.06317-1.348-9.86325-3.33707-14.4004-5.9673-4.53712-2.6302-8.6961-5.88506-12.47704-9.76464-3.78094-3.87957-6.98648-8.21937-9.6167-13.01953-1.0521-1.51237-1.57812-3.3535-1.57812-5.52343 0-2.959.98633-5.40835 2.959-7.34814 1.97266-1.9398 4.43845-2.90967 7.39745-2.90967 1.97267 0 3.6001.46028 4.88233 1.38086 1.28223.92058 3.04116 2.95897 5.27685 6.11524 2.2357 3.15626 4.20833 5.5563 5.91797 7.2002 7.49613 7.49612 16.53738 11.24413 27.12402 11.24413 10.6524 0 19.66077-3.68227 27.0254-11.0469 4.53713-5.52346 6.80566-10.88245 6.80566-16.07714v-11.7373zm56.71387-124.7705v62.73046h19.92382c4.2741 0 8.30158-.82193 12.08253-2.46582 3.78094-1.64387 7.10154-3.87953 9.9619-6.70702 2.86037-2.82748 5.1289-6.1481 6.80567-9.9619 1.67677-3.81383 2.51514-7.8906 2.51514-12.23048 0-4.40563-.83835-8.5153-2.51512-12.3291-1.67676-3.81383-3.9453-7.13444-6.80566-9.96192-2.86036-2.8275-6.1974-5.0467-10.01122-6.65772-3.81382-1.611-7.82485-2.4165-12.0332-2.4165h-19.92383zM672.7754 194.54492V57.64258c0-1.44662.263-2.81103.78905-4.09326.52605-1.28224 1.2658-2.40006 2.21924-3.35352.95344-.95345 2.05483-1.6932 3.3042-2.21924 1.24934-.52604 2.6302-.78906 4.14256-.78906h30.3789c4.7344 0 9.32078.62467 13.75928 1.87402 4.4385 1.24936 8.59748 3.02473 12.47705 5.32618 3.87957 2.30144 7.43032 5.0467 10.65234 8.23584 3.22202 3.18914 5.96727 6.72345 8.23584 10.60302 2.26855 3.87958 4.04393 8.03855 5.32616 12.47705 1.28223 4.4385 1.92334 9.0249 1.92334 13.7593 0 14.3347-5.16173 26.6637-15.48535 36.9873-10.1921 10.1921-22.4882 15.2881-36.88868 15.2881h-19.92382v42.80663c0 2.89325-1.0192 5.35904-3.05762 7.39746-2.0384 2.0384-4.5042 3.0576-7.39743 3.0576-2.89324 0-5.35904-1.0192-7.39746-3.05762-2.0384-2.03842-3.0576-4.5042-3.0576-7.39746zm135.0283-119.6416c0 3.35353-1.18357 6.21386-3.55077 8.58106-2.3672 2.3672-5.22752 3.55078-8.58105 3.55078-3.35354 0-6.21386-1.1836-8.58106-3.5508-2.3672-2.36718-3.55078-5.2275-3.55078-8.58104 0-3.35353 1.18358-6.21385 3.55078-8.58105 2.3672-2.3672 5.22752-3.5508 8.58105-3.5508 3.35354 0 6.21386 1.1836 8.58106 3.5508 2.3672 2.3672 3.55078 5.22752 3.55078 8.58105zm-22.38964 119.74023V104.8877c0-2.89325 1.00276-5.3426 3.0083-7.34815 2.00555-2.00554 4.42203-3.0083 7.2495-3.0083 2.8275 0 5.24398 1.00276 7.24953 3.0083 2.00552 2.00554 3.04116 4.4549 3.1069 7.34814v89.75584c-.06574 2.89325-1.1014 5.3426-3.10692 7.34815-2.00556 2.00553-4.42204 3.0083-7.24952 3.0083-2.8275 0-5.24397-1.00277-7.24952-3.0083-2.00554-2.00556-3.0083-4.4549-3.0083-7.34816zM847.75 104.69043c8.7455-6.77282 19.03607-10.15918 30.87207-10.15918 6.90433 0 13.46335 1.34797 19.67725 4.04395 6.2139 2.69597 11.68796 6.3618 16.42236 10.99755 4.7344 4.63577 8.4824 10.0934 11.24414 16.37305 2.76173 6.27966 4.14258 12.97018 4.14258 20.07178v48.62597c0 2.89325-1.00276 5.3426-3.0083 7.34815-2.00555 2.00554-4.42203 3.0083-7.2495 3.0083-2.89326 0-5.34262-1.00276-7.34816-3.0083-2.00554-2.00555-3.0083-4.4549-3.0083-7.34815V146.0176c0-4.20836-.82193-8.1865-2.46582-11.93457-1.6439-3.74806-3.8631-7.01935-6.65772-9.81396-2.7946-2.7946-6.0659-5.01382-9.81396-6.6577-3.74806-1.6439-7.72622-2.46583-11.93457-2.46583-4.2741 0-8.2687.8055-11.9839 2.4165-3.71517 1.61102-6.98646 3.83024-9.81395 6.65773-2.8275 2.82748-5.0467 6.1152-6.65772 9.86328-1.611 3.74807-2.4165 7.72622-2.4165 11.93458v48.62597c0 2.89325-1.00276 5.3426-3.0083 7.34815-2.00554 2.00554-4.42202 3.0083-7.2495 3.0083-2.89326 0-5.3426-1.00276-7.34816-3.0083-2.00554-2.00555-3.0083-4.4549-3.0083-7.34815v-89.7559c0-2.8275 1.00276-5.2604 3.0083-7.29883 2.00555-2.03842 4.4549-3.05762 7.34815-3.05762 2.82747 0 5.24395 1.0192 7.2495 3.05762s3.0083 4.40558 3.0083 7.10156zm153.07812 10.45508c-4.8659 0-9.40297.92058-13.61132 2.76174-4.20836 1.84115-7.85774 4.3234-10.94825 7.44677-3.0905 3.1234-5.53986 6.7892-7.34814 10.99757-1.80826 4.20836-2.7124 8.67967-2.7124 13.41406 0 4.7344.90414 9.2057 2.7124 13.41407 1.8083 4.20834 4.25765 7.87416 7.34817 10.99755 3.0905 3.12338 6.73988 5.60562 10.94824 7.44677 4.20836 1.84116 8.7454 2.76172 13.61133 2.76172 4.80016 0 9.30435-.92056 13.5127-2.76172 4.20835-1.84115 7.87417-4.33982 10.99756-7.4961 3.1234-3.15626 5.58917-6.82207 7.39745-10.99755 1.80828-4.17548 2.7124-8.63035 2.7124-13.36474 0-4.7344-.90412-9.18927-2.7124-13.36475s-4.27407-7.8413-7.39746-10.99756c-3.1234-3.15626-6.7892-5.65494-10.99757-7.4961-4.20835-1.84115-8.71254-2.7617-13.5127-2.7617zm34.62012 77.72267C1025.5849 200.9561 1014.045 205 1000.82812 205c-15.25528 0-28.27468-5.39187-39.0586-16.17578-10.7839-10.7839-16.17577-23.8033-16.17577-39.0586 0-15.25528 5.39187-28.27468 16.17578-39.0586 10.7839-10.7839 23.8033-16.17577 39.0586-16.17577 15.12377 0 28.14317 5.39187 39.0586 16.17578 10.7839 10.7839 16.17577 23.8033 16.17577 39.0586v54.83984c0 4.7344-.7233 9.2057-2.16992 13.41406-1.44662 4.20836-3.45214 8.07144-6.0166 11.58936-2.56447 3.5179-5.58918 6.69055-9.07422 9.51804-3.48505 2.8275-7.2495 5.2111-11.29346 7.15088-4.04396 1.9398-8.2687 3.4357-12.67432 4.4878-4.40562 1.05208-8.81117 1.57812-13.2168 1.57812-5.26043 0-10.42217-.67398-15.48534-2.02197-5.06318-1.348-9.86326-3.33707-14.4004-5.9673-4.53713-2.6302-8.6961-5.88506-12.47704-9.76464-3.78095-3.87957-6.98648-8.21937-9.6167-13.01953-1.0521-1.51237-1.57813-3.3535-1.57813-5.52343 0-2.959.98632-5.40835 2.95898-7.34814 1.97267-1.9398 4.43847-2.90967 7.39747-2.90967 1.97266 0 3.6001.46028 4.88232 1.38086 1.28223.92058 3.04117 2.95897 5.27685 6.11524 2.23567 3.15626 4.2083 5.5563 5.91795 7.2002 7.49613 7.49612 16.5374 11.24413 27.12403 11.24413 10.65238 0 19.66076-3.68227 27.02538-11.0469 4.53713-5.52346 6.80566-10.88245 6.80566-16.07714v-11.7373z"/>
    </g>
</svg>

Do you already see the advantage? I really like it. We can add a class or/and a style variable in there. And what we now can do is include this file in our template and override the class or/and styleattribute as we need. Awesome!

Here is, what it looks like in our welcome.blade.php.

<!DOCTYPE html>

<!-- ... -->

<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="csrf-token" content="{{ csrf_token() }}">

    <title>Login</title>

    <link href="https://fonts.googleapis.com/css?family=Lato:300,400,700" rel="stylesheet">
</head>
<body class="bg-grey-lighter text-base text-grey-darkest font-normal relative">
    <div class="h-2 bg-primary"></div>

    <div class="container mx-auto p-8">
        <div class="mx-auto max-w-sm">
            <div class="py-10 text-center">
                @include('logo', ['style' => 'max-width: 12rem;'])
            </div>

            <!-- ... -->

            <div class="bg-white rounded shadow">
                <div class="border-b py-8 font-bold text-black text-center text-xl tracking-widest uppercase">
                    Welcome back!
                </div>

                <form class="bg-grey-lightest px-10 py-10">
                    {{ csrf_field() }}

                    <div class="mb-3">
                        <input class="border w-full p-3" name="email" type="text" placeholder="E-Mail">
                    </div>
                    <div class="mb-6">
                        <input class="border w-full p-3" name="password" type="password" placeholder="**************">
                    </div>
                    <div class="flex">
                        <button class="bg-primary hover:bg-primary-dark w-full p-4 text-sm text-white uppercase font-bold tracking-wider">
                            Login
                        </button>
                    </div>
                </form>

                <div class="border-t px-10 py-6">
                    <div class="flex justify-between">
                        <a href="#" class="font-bold text-primary hover:text-primary-dark no-underline">Don't have an account?</a>
                        <a href="#" class="text-grey-darkest hover:text-black no-underline">Forgot Password?</a>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <!-- ... -->
</body>
</html>

The result

I think we're done for now. This is what we have built today, it's a little bit different from the initial sketch, but I think this is fine. I hope you like it.

Feedback

This episode was really hard for me because I am not sure what you're interested in, and what you're not. I am not sure about how deep I should explain something. Are my readers' beginners, intermediates, or experts?

I would like to learn more about you. So just contact me via Twitter and let me know what you think.

Only if I know what I can do better can I improve my episodes, and show you what you really like.

Bobby Bouwmann and I are writing a book called "Laravel Secrets".
You will learn everything about the undocumented secrets of the popular Laravel framework. You can sign up using the form below to get early updates.
      Visit laravelsecrets.com to get more information.