Kutty is a tailwind plugin for building web applications. It has a set of accessible and reusable components that are commonly used in web applications.

  • By Praveen Juge
  • Last update: Dec 27, 2022
  • Comments: 13


Kutty is a tailwind plugin for building web applications. It has a set of accessible and reusable components that are commonly used in web applications.


npm install kutty --save

This plugin requires Tailwind CSS 3 or later. Tailwind CSS is not included in this package. Learn how to install tailwind here.



Require the installed plugin directly to your Tailwind config:

// tailwind.config.js
plugins: [require("kutty")],

For JS

We bundle AlpineJS v2.8.0 for reactivity in our components. Learn more about AlpineJS here. Place the following script tag before the closing body tag.

<!-- All components in one -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/kutty.min.js"></script>
<!-- Single component -->
<!-- Include AlpineJS first -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/alpinejs.min.js"></script>
<!-- And then the single component -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/dropdown.min.js"></script>


View full documentation at https://kutty.netlify.app.

Bugs & Suggestions

Found a bug? Please open a new issue. Use GitHub Discussions for new feature requests.


You need Hugo to run the dev server. If you have Homebrew you can do the following:

brew install hugo

Check this Hugo installation page for installing on other systems.

Then clone the repo, install dependencies, and start the server locally.

git clone https://github.com/praveenjuge/kutty.git
cd kutty
npm install
npm start

Open http://localhost:1313 in your browser.

Scripts Description
npm start Starts a local Hugo server and Tailwind Watcher
npm run production For generating production docs files


See the LICENSE file.




  • 1

    Open dialog creates scroll bar

    For a page that does not have a scroll bar, everything gets shifted slightly to the left when the dialog opens, as a scrollbar is created.

    Before image

    After image Note the white bar on the far right.

    Is there any way to prevent this behavior?

  • 2

    Error in tailwinds-intellisense

    When we add the fluky plugin in a Phoenix application, the tailwindcss intelligence stops working VS Code.

    Gives errors like: "tailwind CSS: :1:8: The focus:ring class does not exist. If you're sure that focus:ring exists, make sure that any @import statements are being properly processed before Tailwind CSS sees your CSS, as @apply can only be used for classes in the same CSS tree."

    The extension works, only the VS Code extension is affected.

  • 3

    Cannot initialize dropdowns with Alpine


    I'm currently using Kutty within a Nuxt app, but I cannot get the dropdowns to work ,since I'm getting Uncaught ReferenceError: dropdown is not defined on the JS console every time. Could it be something related to Alpine JS?

    Thanks in advance and awesome job with Kutty!

  • 4

    No Badge class styles

    I've found that when I use a blog post component from https://kutty.netlify.app/components/blog-post/ That the styles for the badge don't come through. As if the class is not there. Is there something I'm missing? All the other styles seem to come through.

    I'm running:

        "autoprefixer": "^10.2.5",
        "next": "10.0.4",
        "postcss": "^8.2.8",
        "react": "17.0.1",
        "react-dom": "17.0.1",
        "tailwindcss": "^2.0.3"

    Next JS

    Is it from tailwind UI? https://tailwindui.com/components/application-ui/elements/badges

  • 5

    Can't click buttons in drawer on mobile Safari

    Hello, It is impossible to click save changes button in drawer opened in Safari browser on iOS. Buttons is hiding behind browser's UI and scrolling is impossible when drawer is opened. But when I can see the buttons, they are so low that I trigger browser UI instead of clicking on buttons. This is a link to video presenting the issue: https://youtu.be/F8P2cbAt4xo

  • 6

    Page with multiple dialogs

    On my page, I have two separate dialogs that host different content.

    When I trigger one of the dialogs, it can only be closed by clicking outside it (not on the X or close buttons implemented - it's a near-copy of the dialog in the docs). When I click on the other dialog, it can only be closed by clicking on the X or close button, not by clicking outside.

    Is there any way to have multiple dialogs on the same page, or does the code need to be rewritten to have a dynamic dialog?

  • 7

    Tooltips show up twice after some time

    If you create a tooltip using Kutty, after a few seconds have passed, a tooltip will also show up using the default CSS pointer event.

    This action cannot be overcome without also disabling Kutty tooltip (see this StackOverflow post).

    If you go to Kutty Docs and hover over a tooltip for some time you can see it also shows up. Demonstrated in image below.

    Ideal solution would be to use a different HTML element parameter than title for the x-data title, so that this "double tooltip title" error doesn't show up.


  • 8

    Detail Vue Setup

    Some of Kutty's dynamic components and features won't work, as they use an AlpineJS shorthand that clashes with Vue. I have added a bit to the docs showing how to overcome this by removing the shorthand.

  • 9

    Can Kutty be used with Vite?

    I tried to use with this template (Vitesse), and for some reasons errors appear after adding Kutty in tailwind.config.js

    Vitesse is an opinionated vite template. https://github.com/antfu/vitesse


  • 10

    Calling show on dialog from external component

    Hi, can you help with this :

    I would like to call the dialog component from a livewire component that can pass value to alpine (i assume you're using it in your components), what is the value of x-data and x-show to use to trigger dialogs ?

    Thanks and keep up the good work !!

  • 11

    error on collapse

    using collapse I receive this error from alpine dev tool :

    Alpine Error: "ReferenceError: collapse is not defined

    both using the single component and the sidebar page

    Thanks !

  • 12

    Suggestion: Decouple framework specific aspects.

    Kutty seems to be created with Alpine.js, and while it's a great library, not everyone is using it and it's just dead code if they import Kutty into their project solely for the TailwindCSS configuration just to implement their own components in React, Vue, or whatnot.

    And so in my opinion; Alpine.js should not be a requirement for this project by default, and that logic should be seperated into their own areas, and perhaps even implement React, vue, ect variants.

    Let me know on your thoughts, thanks!

  • 13

    Trigger JS components from outside Alpine

    Hi, I would like to trigger a JS component like dropdown or dialog from "outside" the component, in particular from an event handler of an element which is not handled by the component itself. This would mean not using the trigger button allowing normally to open the dialog as shown in the examples.

    The specific use case is that I'm using an external library (http://tabulator.info/) that generates some "action buttons" in a cell of the table, and I would like to trigger the opening of the dialog when clicking on that action button.

    What I would like to do (pseudo-code imitating a React-like UI lib):

    <button on:click={(event) => {
      dialogElement.sendToAlpine("open") // or something like that!
    <div ref={dialogElement} x-data="dialog()">
      // There is no trigger button here
      <div class="dialog" x-spread="dialog" x-cloak>
        <div class="dialog-content">

    Is it possible as-is, or by adapting the Alpine components of dialog/dropdown/etc? Or should I rewrite the JS components using Svelte/Vue/React?

    I dived into the JavaScript code (e.g. dialog.js) and tried to hack around with Svelte, here is what I did on Svelte REPL.

    This works but is in my sense a bit "overkill" and has remaining questions/problems:

    • that's strange to have to put the trigger button inside the dialog
    • how to close the dialog from a Svelte event handler?
    • the dialogAction function feels quite hacky
    • overall it does not solve the use case explained above: I still have to render the trigger button as a child of <div x-spread="trigger">, otherwise the Alpine component won't see it

    Afterthought: would it be possible to break the Alpine JS components into base functions that could still be called by the Alpine JS components, but could be also be called by Svelte/Vue/React components?

    Anyway, thanks for the excellent work and for your reactivity about following Tailwind v2 release!