Part of the appeal of Smelte was Tailwind CSS integration. After going back and trying Smelte some more, I concluded that it’d be easier to use Tailwind directly, at the cost of giving up some very convenient widtgetry. The Smelte widgets aren’t comprehensive enough to use them all alone, and their customization of Tailwind makes it too hard to integrate things that rely on the vanilla utility classes. So here’s how I’m integrating.

I had heard of Tailwind before trying Smelte, but it wasn’t really on my radar. After struggling some with Smelte and what seemed to be nondeterministic postprocessing, I concluded that my widget needs are relatively simple and it’s less trouble to just use the Tailwind utility classes directly. None of the documentation I could find seems to have the whole story, though. With the abundance of yaks hanging around as I learn about the space, I can’t resist shaving this one.

This post borrows heavily from @sarioglu’s article here and @inalbant’s article here. The former integrates svelte’s preprocessor and the latter integrates Tailwind’s relatively new PurgeCSS support. Apart from combining those two features, I’ve also updated the tailwind configuration according to the current Tailwind CSS documentation as of 8 October 2020.

Project setup

I’m working in my stock toolkit project, starting from the tag following the notionally feature-complete backend. From within that tree, I grab the svelte template:


$ npx degit sveltejs/template
$ npm i

I optimistically update package.json with a project name and drop a favicon into the public directory along with an updated link to make it easier to spot among my dozen+ browser tabs. Then I run the watcher and uvicorn and make sure the template is working. It is.

Then I install taiwind in my dev tree along with the postcss CLI and the svelte preprocessor. The cli is necessary for tailwind’s integrated PurgeCSS support, and the preprocessor is necessary to get @apply in style blocks within .svelte files. draft = true

module.exports = {
  future: {
    removeDeprecatedGapUtilities: true,
    purgeLayersByDefault: true,
  },
  purge: {
    enabled: true,
    content: ["./src/**/*.svelte"],
  },
  theme: {
    extend: {},
  },
  variants: {},
  plugins: [],
}

Update, 10/15/2020: Further work on the stock toolkit has led to some more changes to the tailwind configuration in order to adopt the UI plugin, the elevation plugin and the forms plugin.

Here’s my new full tailwind.config.js:

/* XXX *** When I have purge problems, look at the github issue mentioned here:
https://dev.to/swyx/how-to-set-up-svelte-with-tailwind-css-4fg5
*/
module.exports = {
  future: {
    removeDeprecatedGapUtilities: true,
    purgeLayersByDefault: true,
  },
  purge: {
    //enabled: true,
    content: ["./src/**/*.svelte"],
  },
  theme: {
    extend: {
      // work-around described in https://github.com/tailwindlabs/tailwindcss-custom-forms/issues/27
      customForms: theme => ({
        default: {
          checkbox: {
            '&:indeterminate': {
              background: 'url("data:image/svg+xml,%3Csvg viewBox=\'0 0 16 16\' fill=\'white\' xmlns=\'http://www.w3.org/2000/svg\'%3E%3Crect width=\'8\' height=\'2\' x=\'4\' y=\'7\' rx=\'1\'/%3E%3C/svg%3E");',
              borderColor: 'transparent',
              backgroundColor: 'currentColor',
              backgroundSize: '100% 100%',
              backgroundPosition: 'center',
              backgroundRepeat: 'no-repeat',
            }
          }
        }
      })
    },
  },
  variants: {},
  plugins: [
    require('@tailwindcss/ui'),
    require('tailwindcss-elevation')(['responsive', 'hover', 'focus', 'active']),
    require('@tailwindcss/custom-forms'),
  ],
}

And I set up the tailwind plugin in postcss.config.js:

const tailwindcss = require("tailwindcss")

module.exports = {
    plugins: [
        tailwindcss("./tailwind.config.js")
    ],
}

Finally, to get @apply in svelte files, I need to modify rollup.config.js by adding an instance of svelte-preprocess at the top:

import svelte from 'rollup-plugin-svelte';

and adding it as a parameter to the svelte plugin

plugins: [
    //...
    svelte({
        //...
        preprocess: sveltePreprocess({postcss: true}),
        //...
    }),
]

Using Tailwind CSS in Svelte Components

Delete src/global.css and the link to it from src/index.html. Tailwind does that reset for us now.

Create src/Tailwindcss.svelte to apply Tailwind CSS globally:

<style global>
    @tailwind base;
    @tailwind components;
    @tailwind utilities;
</style>

and modify src/App.svelte to import and use it:

<script>
    import Tailwindcss from './Tailwindcss.svelte';
</script>
<style>
    .orangeblack {
        @apply bg-orange-600 text-gray-900
    }
</style>
<div class="orangeblack">
    <h1 class="text-2xl font-bold">Hello, Tailwind CSS</h1>
</div>

My working tree with this configuration can be found here.