The forms plugin has a strategy option, and test is a script that exits zero
A plugin that provides a basic reset for form styles that makes form elements easy to override with utilities.
At a glance
- What is it?
- @tailwindcss/forms normalizes seventeen form element types so utilities can style them, and generates a matching set of form-* classes you can apply by hand. Both halves ship at once unless you pick a strategy, and the package has no test suite.
- Who is it for?
- Use tailwindcss-forms if you want one stylesheet-level reset so `px-4 py-3 rounded-full` works on a select or a checkbox, rather than writing appearance rules yourself. Do not treat it as a form component library, since it produces no markup and no variants, only base styles plus classes.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Activity is slowing. The repository last received commits 6 months ago.
- What is it written in?
- Mainly HTML, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.
Star history
- tailwindlabs/tailwindcss-forms4,558 ★ · -9
| Repository | 2026-09-23 | 2026-11-14 |
|---|---|---|
| tailwindlabs/tailwindcss-forms | 4.6k | 4.6k |
-9 Stars in the last 52 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
The plugin emits both base styles and form-* classes, and the strategy option picks one
This plugin generates two things at once, and that is the decision you have to make before using it.
By default it produces global base styles that apply to form elements wherever they appear, plus a set of classes you can apply explicitly. The README recommends thinking of it as a form reset rather than a collection of form component styles, and then immediately acknowledges that the default approach may be too heavy-handed in some cases, especially when integrating into existing projects.
The `strategy` option is the escape hatch. With Tailwind CSS v4 it goes in the stylesheet.
/* app.css */
@plugin "@tailwindcss/forms" {
strategy: "base"; /* only generate global styles; or */
strategy: "class"; /* only generate classes */
}The two outcomes are symmetrical. Under `base`, form elements are styled globally and no `form-{name}` classes are generated. Under `class`, form elements are not styled globally and must be styled using the generated classes.
That symmetry is the point. On a greenfield project the default is convenient because every input looks reasonable before you style it. On an existing codebase the global half reaches markup you did not write, and `class` is almost always the answer.
Installation differs between v3 and v4, and the plugin declares support for both
Install is one npm command.
npm install -D @tailwindcss/formsThen the registration depends on your Tailwind major version. On v4 it goes in the main stylesheet.
/* app.css */
@import "tailwindcss";
@plugin "@tailwindcss/forms";On v3 it goes in the config file.
// tailwind.config.js
module.exports = {
theme: {
// ...
},
plugins: [
require('@tailwindcss/forms'),
// ...
],
}The peer dependency range in package.json is written to cover both, listing `>=3.0.0 || >= 3.0.0-alpha.1 || >= 4.0.0-alpha.20 || >= 4.0.0-beta.1`. That range includes three alpha and beta windows, which tells you the v4 support was added while v4 was still pre-release and then kept rather than narrowed.
Worth noting for anyone pinning: the package itself is at version 0.5.11, the entry point is `src/index.js` with types at `src/index.d.ts`, and the only runtime dependency is `mini-svg-data-uri`. The rest, autoprefixer, concurrently, live-server, postcss, prettier, prettier-plugin-tailwindcss and tailwindcss, are development dependencies.
One inconsistency to be aware of: the development dependency is `tailwindcss: ^3.0.24`, so the plugin is built against v3 locally even though it supports v4.
The payoff is that padding and text colour utilities reach elements that usually resist them
The reason a reset exists at all is that several form elements ignore the CSS you write against them.
A select normally needs `appearance: none` and a set of custom rules before it can be styled. A checkbox normally resists background colour entirely. The plugin normalizes these so the utilities you already know start working.
<!-- You can actually customize padding on a select element now: -->
<select class="rounded-full px-4 py-3">
<!-- ... -->
</select>
<!-- Or change a checkbox color using text color utilities: -->
<input type="checkbox" class="rounded text-pink-500" />The checkbox example is the more striking one. `text-pink-500` changes a checkbox's colour, which is not something you can do with utilities on a stock checkbox.
Seventeen element types are covered: the text-like inputs covering text, password, email, number, url, date, datetime-local, month, week, time, search and tel, then checkbox, radio, select, select with multiple, and textarea.
What is not covered is the file input and the range input. Neither appears in the list, so if your design has a custom file picker or a styled range slider, this plugin does not normalise those and you still write the reset yourself.
The class table maps twelve input types to one class, and multiselect has its own
The generated classes exist for two cases: applying form styling to a non-form element, and opting into styling per element when the global reset is off.
<input type="email" class="form-input rounded-full px-4 py-3" />
<select class="form-select rounded-full px-4 py-3">
<!-- ... -->
</select>
<input type="checkbox" class="form-checkbox rounded text-pink-500" />The naming is regular with one exception worth knowing. All twelve text-like input types share `form-input`, so `input[type='email']`, `input[type='url']`, `input[type='password']`, `input[type='number']`, the date family, `input[type='search']`, `input[type='tel']`, `input[type='time']` and `input[type='week']` all take the same class. `textarea` takes `form-textarea`, plain `select` takes `form-select`, `[type='checkbox']` takes `form-checkbox` and `[type='radio']` takes `form-radio`.
The exception is `select[multiple]`, which gets `form-multiselect` rather than `form-select`. That is a separate class with a separate reset, so a multiple select is not covered by adding `form-select`.
The stated use for the classes is making a non-form element look like a form element, for instance giving a `<div>` the appearance of an input. That is what makes the explicit classes more than a workaround for the strategy setting.
The package test script is exit 0, so there is no suite protecting these selectors
In package.json, the scripts block includes one line that deserves attention.
"test": "exit 0"That is the whole test script. It succeeds unconditionally, so `npm test` passing tells you nothing about whether the plugin works.
The rest of the scripts are ordinary for a plugin repository. `build` runs the Tailwind CLI to output `dist/tailwind.css`. `dev` runs `serve` and `watch` concurrently, where `serve` is a live server on the current directory and `watch` is the build with a watch flag. There is also a prettier format script and two release helpers, `release-channel` and `release-notes`, both node scripts under `scripts/`.
There is a demo you can look at instead. The repository root has `index.html` and `kitchen-sink.html`, and the published demo is at tailwindcss-forms.vercel.app. `kitchen-sink.html` is the more useful of the two for judging whether the reset suits your taste, since a kitchen sink is exactly the case where a global reset either holds up or becomes obvious clutter.
So the verification story for this plugin is visual. Open the demo, open your own page with the plugin installed, and compare. There is no automated check to fall back on.
Version 0.5.11 shipped in December 2025 and the last push was in May 2026
The release history is slow and the commit history is steadier.
Version 0.5.9 published 2024-09-05, 0.5.10 on 2025-01-07, and 0.5.11 on 2025-12-17. That is roughly four months between 0.5.9 and 0.5.10, then eleven months until 0.5.11. The last push to the repository was 2026-05-12.
For a plugin whose job is a CSS reset, that cadence is unremarkable. A form reset is not something that needs to change often, and the code is generated CSS output rather than runtime logic. But it does mean you should not expect a new selector to appear when you need one.
The licence is MIT, and the repository carries a CHANGELOG.md and a LICENSE file at the root alongside the source directory.
What the README does not document is worth naming so you do not go looking. There is no stated browser support matrix, no note about how the plugin interacts with other Tailwind plugins that also touch base styles, and no accessibility guidance for the appearance reset. That last one is the real gap for a library that sets `appearance` on native controls: the README explains how to make the elements look like you want but does not say anything about whether the reset preserves the focus indicators or the semantics that the platform provides.
It produces styles, not components, so there is no markup or state to copy
The clearest way to set expectations is what this plugin is not.
There is no component here. You do not get a React or Vue component, no template, no wrapper markup, no label, no error message slot, no focus or invalid state as a variant. What comes out of the build is CSS.
That has a direct consequence for how you use it. Writing a login form with this plugin still means writing every input, every label, and every bit of layout yourself. What changes is that each input is already normalized, so the classes you write do something.
It also means there is nothing to configure per component. No props, no theme keys under `theme.extend` for form elements, no variants like `form-input-lg`. The only configuration surface documented is the `strategy` option.
If you want a styled input with an error state and a leading icon, you are still assembling that. This plugin removes the reset work underneath and leaves composition to you.
The README itself frames the scope that way, describing it as a basic reset that makes form elements easy to override with utilities, and noting that more customization examples and best practices are coming soon.
Editorial conclusion
Use tailwindcss-forms if you want one stylesheet-level reset so `px-4 py-3 rounded-full` works on a select or a checkbox, rather than writing appearance rules yourself. Do not treat it as a form component library, since it produces no markup and no variants, only base styles plus classes. Verify first which strategy your project needs: the default generates both global base styles and form-* classes, and on an existing codebase that global half is the part most likely to conflict with what you already have, so pick `class` there. Note also that the package's test script is `exit 0`.
Frequently asked questions
What are Tailwind CSS forms?
The @tailwindcss/forms package is a Tailwind plugin providing a basic reset for form styles. It normalizes seventeen form element types, from text-like inputs through select, checkbox, radio and textarea, so utilities like padding and text colour can style them.
What is the tailwindcss-forms plugin and how is it installed?
It is a plugin that provides a basic reset for form styles, making form elements easy to override with utilities. Install it with `npm install -D @tailwindcss/forms`, then register it with `@plugin "@tailwindcss/forms"` in your stylesheet on v4, or with `require('@tailwindcss/forms')` in tailwind.config.js on v3.
How do I install the Tailwind CSS forms plugin?
Run `npm install -D @tailwindcss/forms`. On Tailwind CSS v4 add `@plugin "@tailwindcss/forms"` to your main stylesheet after importing tailwindcss. On Tailwind CSS v3 add `require('@tailwindcss/forms')` to the plugins array in tailwind.config.js.
What does the strategy option do in tailwindcss-forms?
It limits the plugin to generating only global base styles or only the explicit form-* classes. With `strategy: 'base'` form elements are styled globally and no form-* classes are generated. With `strategy: 'class'` the reverse applies and elements must be styled using those classes.
Which form-* classes does tailwindcss-forms provide?
All twelve text-like input types share `form-input`. Then `textarea` maps to `form-textarea`, `select` to `form-select`, `select[multiple]` to `form-multiselect`, `[type='checkbox']` to `form-checkbox` and `[type='radio']` to `form-radio`.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/tailwindlabs-tailwindcss-forms)Star history chart for your README
[](https://hysenlabs.com/projects/tailwindlabs-tailwindcss-forms)Was this useful?