Vue-Tailwind
For more info, check the official site: https://vue-tailwind.com/.
VueTailwind is a set of Vue components created to be customized to adapt to your application's unique design.
Another UI library?
Most component libraries depend on CSS frameworks with an opinionated and limited number of styles defined by the people who maintain those libraries.
Those libraries are great and make our work easy, but hey, we made a beautiful custom design, right?
So what are the alternatives?
We can use a framework like TailwindCss to define our style, but that will end with us writing long CSS classes repeatedly, which could quickly become unmaintainable. Also, create some components like modals, date pickers, etc., is a tricky task, and let's admit it, nobody has time for that, right?
Best of both worlds
The VueTailwind components are meant to be customized with custom CSS classes that you can define when you install the library.
Plus, most component settings are configurable, so using this library is like having your personal set of components for your particular needs.
All that means that with this library, you will be able to:
- Define your components look and feel by defining custom default CSS classes.
- Add unlimited variants for every specific use case.
- Override the default value of the props according to your needs.
- Create different versions of one component with different default settings.
Installation
1. Install the dependencies
npm install vue-tailwind --save
Or:
yarn add vue-tailwind
2. Install TailwindCSS (Optional)
This library uses TailwindCSS classes by default. Still, it should work with any CSS framework since all the CSS classes are configurable.
To install TailwindCSS follow his official documentation: https://tailwindcss.com/docs/installation
2.1 Add the @tailwindcss/forms plugin
The default theme of this library depends on the @tailwindcss/forms
plugin. To use it, follow the steps on the plugin source page. https://github.com/tailwindlabs/tailwindcss-forms
2.1 Add variants for disabled pseudo-class
Also needed for the default theme and strongly recommended since it adds the ability to use some classes like disabled:opacity-50 disabled:cursor-not-allowed
to disabled inputs.
See https://tailwindcss.com/docs/configuring-variants on the TailwindCSS docs for more info.
As a reference, your tailwind.config.js
may look like this:
module.exports = {
variants: {
extend: {
opacity: ['disabled'],
cursor: ['disabled'],
},
},
plugins: [
require('@tailwindcss/forms'),
],
};
3. Configure Vue to use vue-tailwind
import Vue from 'vue'
import VueTailwind from 'vue-tailwind'
const components = {
// ...You need to add the components you need here (explained above)
}
Vue.use(VueTailwind, components)
3.1 Import and install the components
import Vue from 'vue'
import VueTailwind from 'vue-tailwind'
import {
TInput,
TTextarea,
TSelect,
TRadio,
TCheckbox,
TButton,
TInputGroup,
TCard,
TAlert,
TModal,
TDropdown,
TRichSelect,
TPagination,
TTag,
TRadioGroup,
TCheckboxGroup,
TTable,
TDatepicker,
TToggle,
TDialog,
} from 'vue-tailwind/dist/components';
const settings = {
// Use the following syntax
// {component-name}: {
// component: {importedComponentObject},
// props: {
// {propToOverride}: {newDefaultValue}
// {propToOverride2}: {newDefaultValue2}
// }
// }
't-input': {
component: TInput,
props: {
classes: 'border-2 block w-full rounded text-gray-800'
// ...More settings
}
},
't-textarea': {
component: TTextarea,
props: {
classes: 'border-2 block w-full rounded text-gray-800'
// ...More settings
}
},
// ...Rest of the components
}
Vue.use(VueTailwind, settings)
3.2 Alternatively, you can use the v1.0 syntax
import Vue from 'vue'
// Notice that I am using a different path here:
import VueTailwind from 'vue-tailwind/dist/full'
const settings = {
TInput: {
classes: 'border-2 block w-full rounded text-gray-800',
// ...More settings
},
TButton: {
classes: 'rounded-lg border block inline-flex items-center justify-center',
// ...More settings
},
// ...Rest of the components
}
Vue.use(VueTailwind, settings)
3.3 Or install only the components you need
import Vue from 'vue'
import VueTailwind from 'vue-tailwind'
import TInput from 'vue-tailwind/dist/t-input'
import TButton from 'vue-tailwind/dist/t-button'
const settings = {
't-input': {
component: TInput,
props: {
classes: 'block w-full px-3 py-2 text-black placeholder-gray-400 transition duration-100 ease-in-out bg-white border border-gray-300 rounded shadow-sm focus:border-blue-500 focus:ring-2 focus:ring-blue-500 focus:outline-none focus:ring-opacity-50 disabled:opacity-50 disabled:cursor-not-allowed',
// ...More settings
}
},
't-button': {
component: TButton,
props: {
classes: 'block px-4 py-2 text-white transition duration-100 ease-in-out bg-blue-500 border border-transparent rounded shadow-sm hover:bg-blue-600 focus:border-blue-500 focus:ring-2 focus:ring-blue-500 focus:outline-none focus:ring-opacity-50 disabled:opacity-50 disabled:cursor-not-allowed',
// ...More settings
}
},
}
Vue.use(VueTailwind, settings)
Note: Using the syntax from point 3.3 is the best way to prevent a big bundle size but only if you import a couple of components. If the number of components you install increases, the recommended way to install them is to use the syntax from the points 3.1 or 3.2 to help the library reuse some code and keep the bundle size at a minimum.
Theming
To apply a custom theme you should play with the classes
, fixedClasses
, and variants
props.
The classes
and fixedClasses
props usually expects an string
with a CSS class for single-tag components (inputs, button, etc.) and an object
for more complex components (modals, datepicker, etc) (see component docs for details).
The variants
props expects an object where every key represents the variant name and every value the classes that will be used when that variant is applied.
Example for a single-tag component:
import Vue from 'vue'
import VueTailwind from 'vue-tailwind'
import TButton from 'vue-tailwind/dist/t-button'
const settings = {
't-button': {
component: TButton,
props: {
// The fixed classes will never change and will be merged with the `classes` value or the active variant
fixedClasses: 'focus:outline-none focus:shadow-outline inline-flex items-center transition ease-in-out duration-150',
// Classes used when any variant is active
classes: 'text-white bg-blue-600 hover:bg-blue-500 focus:border-blue-700 active:bg-blue-700 text-sm font-medium border border-transparent px-3 py-2 rounded-md',
variants: {
// A red variant of the button (applied when `<t-button variant="error" />`)
error: 'text-white bg-red-600 hover:bg-red-500 focus:border-red-700 active:bg-red-700 text-sm font-medium border border-transparent px-3 py-2 rounded-md',
// A green variant of the button (applied when `<t-button variant="success" />`)
success: 'text-white bg-green-600 hover:bg-green-500 focus:border-green-700 active:bg-green-700 text-sm font-medium border border-transparent px-3 py-2 rounded-md',
// ...unlimited variants
}
// ...More settings
}
},
}
Vue.use(VueTailwind, settings)
Example for a complex component:
import Vue from 'vue'
import VueTailwind from 'vue-tailwind'
import TAlert from 'vue-tailwind/dist/t-alert'
const settings = {
't-alert': {
component: TAlert,
props: {
// The fixed classes will never change and will be merged with the `classes` value or the active variant
fixedClasses: {
wrapper: 'rounded p-4 flex text-sm border-l-4',
body: 'flex-grow',
close: 'ml-4 rounded',
closeIcon: 'h-5 w-5 fill-current'
},
classes: {
wrapper: 'bg-blue-100 border-blue-500',
body: 'text-blue-700',
close: 'text-blue-700 hover:text-blue-500 hover:bg-blue-200',
closeIcon: 'h-5 w-5 fill-current'
},
variants: {
danger: {
wrapper: 'bg-red-100 border-red-500',
body: 'text-red-700',
close: 'text-red-700 hover:text-red-500 hover:bg-red-200'
// Notice that I am not defining the `closeIcon` class since we only
// need to write the classes we want to override
},
}
}
},
}
Vue.use(VueTailwind, settings)
Override settings
All the components on this library have default settings added as component props according to how we understand those settings are most commonly used.
I am aware that in many cases is useful to change the default value, so you don't need to add the prop over and over when needed.
import Vue from 'vue'
import VueTailwind from 'vue-tailwind'
import TDatepicker from 'vue-tailwind/dist/t-datepicker'
import TButton from 'vue-tailwind/dist/t-button'
import TModal from 'vue-tailwind/dist/t-modal'
// Locale to eventually replace the default Datepicker locale
import Spanish from 'vue-tailwind/dist/l10n/es'
const settings = {
't-button': {
component: TButton,
props: {
// classes: '...',
// variants: '...',
// ...
// Originally it defaults to `undefined` that means is considered a submit
// button if the button is inside a form.
type: 'button',
}
},
't-datepicker': {
component: TDatepicker,
props: {
// classes: '...',
// variants: '...',
// ...
// Originally a locale object with English values
locale: Spanish,
}
},
't-modal': {
component: TModal,
props: {
// classes: '...',
// variants: '...',
// ...
// Originally `true`
escToClose: false,
}
},
}
Vue.use(VueTailwind, settings)
You can also use this feature to create different versions of the same component.
import Vue from 'vue'
import VueTailwind from 'vue-tailwind'
import TButton from 'vue-tailwind/dist/t-button'
import TTag from 'vue-tailwind/dist/t-tag'
const settings = {
// What about one <t-button /> for normal button and a `<t-submit />` for a submit button
't-button': {
component: TButton,
props: {
type: 'button',
}
},
't-submit': {
component: TButton,
props: {
type: 'submit',
}
},
// I love this use case for the TTag component and will let you guess what
// is doing: 👇
'blog-title': { // Used like <blog-title>Title of a blog post</blog-title>
component: TTag,
props: {
tag: 'h1',
classes: 'font-semibold text-xl leading-6',
}
},
'blog-subtitle': { // Used like <blog-title>subtitle of a blog post</blog-title>
component: TTag,
props: {
tag: 'h2',
classes: 'font-semibold text-xl leading-6',
}
},
't-link': { // Used like <t-link href="">Open site</t-link>
component: TTag,
props: {
tag: 'a',
classes: 'text-blue-500 underline hover:text-blue-600',
}
}
}
Vue.use(VueTailwind, settings)
Workflow
Once your different variants were defined you can use the variant
prop to define which variant should be applied:
<t-input variant="error" />
The variant prop also accepts an object that takes the first attribute with a truthy value
<t-input
:variant="{
error: inputIsNotValid,
success: inputIsValid,
}"
/>
What's new in version 2.x
- Install only the components you need for smaller bundle size
- Custom name for components
- The ability to install the same component multiple times with different default settings and name
- New default theme
Plans for v3.x
- Rebuild with Vue 3
- Multiple typescript improvements
- Stronger test coverage
- Accesibility first
- New Branding
Contribute
Is this project helpful for you? Consider sponsoring me https://github.com/sponsors/alfonsobries.
Of course, any other kind help is welcome, even if you notice some grammar mistakes (English is not my primary language) see contribute page for details.
Changelog
Please see Release notes for more information about what was changed recently.
Security
If you discover any security related issues, please email [email protected] instead of using the issue tracker.
Credits
License
The MIT License (MIT). Please see License File for more information.
Made with love by @alfonsobries
export 'default' was not found in 'vue-tailwind'
I must be doing something wrong :(
Plain out-of-the-box ~~everything~~ Vue works perfectly 🥳
The minute I try to add ~~something~~Vue Tailwind (2.1.3) - I get this
My app.vue has one added element
and my javascript-pack mentions this
Support for Vue 3?
Hi @alfonsobries
At first. Thank you very much for this awesome library.
I've read that you want to support Vue 3 in the future.
Do you have some more concrete timetable when to release a version for Vue 3?
Can I support you in some way? From coding perspective I haven't enough knowledge about Vue, but perhaps sponsoring you will help the development?
Thanks in advance!
xyNNN
enableBodyScroll unsuccessful on v2
Hey, thanks a lot for the amazing plugin, iv been using since v1 and today i have attempted to updated to v2 beta, and it was a breeze.
Just noticed a little error on the console that seems to root on TModal Component, and wanted to report, not sure if you have noticed:
enableBodyScroll unsuccessful - targetElement must be provided when calling enableBodyScroll on IOS devices
Node 12 VueTailwind 2.0.01 Vue 2
Not sure if this is already fixed on the current pull request but let me know if something needs to be done or set any option.
Once again thanks for the amazing work! :) Keep it up.
Cannot find module '@/types/CssClass'
ERROR in D:/Code/Exenzo/jobboost.io-app/node_modules/vue-tailwind/dist/components/TDatepicker.d.ts(1,43) Cannot find module '@/utils/dates' ERROR in D:/Code/Exenzo/jobboost.io-app/node_modules/vue-tailwind/dist/components/TPagination.d.ts(2,22): Cannot find module '@/types/CssClass'.
And many others, it seems that the internal aliases are not working.
[BUG] Needs to be updated to Vue 2.6.14
Alphonso,
Version 2.3.0 and below will no longer install for the current version of Nuxt (2.15.7) as it requires Vue assets 2.6.14
I think that's all but there could be more.
Unable to use vue-tailwind in nuxt generated app
In my nuxt.js project I am using the datepicker. I import the library as a plugin in this way:
/plugins/vue-tailwind.js
/nuxt.config.js
and the component works perfectly in development.
My problem is that the component is not rendered when I serve the app generated with
I already tried to load the plugin this way:
and also tried to put the component between client-only tag
Rich select does not show selected item on route change
Using TRichSelect on two different pages which vue router load/render them. On first load it works as expected but when navigating to the other page or get back to the current page selected item text is not showing however when I open the select the option is highlighted. Please check screen shots showing selectedOption is not set when it has localValue
Null props error on t-dropdown and t-button (solution mooted)
When I use the t-dropdown component (using examples) I get:
[Vue warn]: Invalid prop: type check failed for prop "href". Expected String with value "null", got Null
Then if I click on the button I get:
[bug] Custom Modal theme not working with dist files
src/main.js
js/plugins/vuetailwind
modal.js
It doesn't work, but when I change it from :
to:
My custom theme works, I'm not sure if this is intentional or not because of the docs doesn't include the /src/index part
https://vue-tailwind.com/#install-and-use
Feature/progress bar
Add Progress Bar component
Question
@alfonsobries A interesting feature/prop with the progress bar could be indeterminate state. To show this state, we could use css animations but tailwind doesn't provide utilities to do that... I'm beginner with tailwind but I think it's possible to use plugins to accomplish what we need. Did you think about a solution ? Let's discuss about it !
before-close doesn't pass event on modals.
Hi!
I'm trying to prevent one of my app's modals from closing, but i'm not receiving the
event
parameter on my event handler. I have no idea of what to do, it just doesn't work :(I'm using the component incorrectly?
Thanks in advance!
Build for production with Vite?
Has anyone gotten this package to work when building for production with Vite?
It seems like Vite is using two different methods to build for dev and prod (with rollup) and it only works for dev for me.
Thanks for tips!
Bump express from 4.17.1 to 4.18.2
Bumps express from 4.17.1 to 4.18.2.
Release notes
Sourced from express's releases.
... (truncated)
Changelog
Sourced from express's changelog.
... (truncated)
Commits
8368dc1
4.18.261f4049
docs: replace Freenode with Libera Chatbb7907b
build: [email protected]f56ce73
build: [email protected]24b3dc5
deps: [email protected]689d175
deps: [email protected]340be0f
build: [email protected]33e8dc3
docs: use Node.js name style644f646
build: [email protected]ecd7572
build: [email protected]Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting
@dependabot rebase
.Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
@dependabot rebase
will rebase this PR@dependabot recreate
will recreate this PR, overwriting any edits that have been made to it@dependabot merge
will merge this PR after your CI passes on it@dependabot squash and merge
will squash and merge this PR after your CI passes on it@dependabot cancel merge
will cancel a previously requested merge and block automerging@dependabot reopen
will reopen this PR if it is closed@dependabot close
will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually@dependabot ignore this major version
will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this minor version
will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this dependency
will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)@dependabot use these labels
will set the current labels as the default for future PRs for this repo and language@dependabot use these reviewers
will set the current reviewers as the default for future PRs for this repo and language@dependabot use these assignees
will set the current assignees as the default for future PRs for this repo and language@dependabot use this milestone
will set the current milestone as the default for future PRs for this repo and languageYou can disable automated security fix PRs for this repo from the Security Alerts page.
Bump qs from 6.5.2 to 6.5.3
Bumps qs from 6.5.2 to 6.5.3.
Changelog
Sourced from qs's changelog.
Commits
298bfa5
v6.5.3ed0f5dc
[Fix]parse
: ignore__proto__
keys (#428)691e739
[Robustness]stringify
: avoid relying on a globalundefined
(#427)1072d57
[readme] remove travis badge; add github actions/codecov badges; update URLs12ac1c4
[meta] fix README.md (#399)0338716
[actions] backport actions from main5639c20
Clean up license text so it’s properly detected as BSD-3-Clause51b8a0b
add FUNDING.yml45f6759
[Fix] fix for an impossible situation: when the formatter is called with a no...f814a7f
[Dev Deps] backport from mainDependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting
@dependabot rebase
.Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
@dependabot rebase
will rebase this PR@dependabot recreate
will recreate this PR, overwriting any edits that have been made to it@dependabot merge
will merge this PR after your CI passes on it@dependabot squash and merge
will squash and merge this PR after your CI passes on it@dependabot cancel merge
will cancel a previously requested merge and block automerging@dependabot reopen
will reopen this PR if it is closed@dependabot close
will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually@dependabot ignore this major version
will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this minor version
will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this dependency
will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)@dependabot use these labels
will set the current labels as the default for future PRs for this repo and language@dependabot use these reviewers
will set the current reviewers as the default for future PRs for this repo and language@dependabot use these assignees
will set the current assignees as the default for future PRs for this repo and language@dependabot use this milestone
will set the current milestone as the default for future PRs for this repo and languageYou can disable automated security fix PRs for this repo from the Security Alerts page.
Bump decode-uri-component from 0.2.0 to 0.2.2
Bumps decode-uri-component from 0.2.0 to 0.2.2.
Release notes
Sourced from decode-uri-component's releases.
Commits
a0eea46
0.2.2980e0bf
Prevent overwriting previously decoded tokens3c8a373
0.2.176abc93
Switch to GitHub workflows746ca5d
Fix issue where decode throws - fixes #6486d7e2
Update license (#1)a650457
Tidelift tasks66e1c28
Meta tweaksDependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting
@dependabot rebase
.Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
@dependabot rebase
will rebase this PR@dependabot recreate
will recreate this PR, overwriting any edits that have been made to it@dependabot merge
will merge this PR after your CI passes on it@dependabot squash and merge
will squash and merge this PR after your CI passes on it@dependabot cancel merge
will cancel a previously requested merge and block automerging@dependabot reopen
will reopen this PR if it is closed@dependabot close
will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually@dependabot ignore this major version
will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this minor version
will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this dependency
will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)@dependabot use these labels
will set the current labels as the default for future PRs for this repo and language@dependabot use these reviewers
will set the current reviewers as the default for future PRs for this repo and language@dependabot use these assignees
will set the current assignees as the default for future PRs for this repo and language@dependabot use this milestone
will set the current milestone as the default for future PRs for this repo and languageYou can disable automated security fix PRs for this repo from the Security Alerts page.
How use t-dropdown in file .tsx
Hello,
I have some problem with t-dropdown. I use .tsx in my nuxt project, i put t-dropdown in render(h){}. but i got error vue warn failed to resolve directive slot.
this my source code for t-dropdown
please help me, thank you
Variants don't work
None of these work for me. Passing a variant removes all default classes. Only if I don't pass any variant it will render something that looks like a button.
Are docs even up to date?
You provide an example https://www.vue-tailwind.com/docs/button with different radio buttons but without any code (usage example). Except "basic example" which doesn't showcase any attributes.