Security News
GitHub Removes Malicious Pull Requests Targeting Open Source Repositories
GitHub removed 27 malicious pull requests attempting to inject harmful code across multiple open source repositories, in another round of low-effort attacks.
the smallest, fastest, most feature complete Tailwind-in-JS solution in existence
If you are here then the likelihood is that you are using Tailwind or a CSS-in-JS solution such as styled-components, Emotion or goober in order to style your web applications. These packages have proven overwhelmingly popular and revolutionized web development as we know it.
The purpose of this project is to unify these two approaches; embracing the flexibility of CSS-in-JS whilst conforming to the carefully considered constraints of the Tailwind API.
We hope to create a place for likeminded people to discuss issues, share ideas and collaborate.
Frequently viewed docs:
twind
setup
If you would like to get started with Twind right away then copy paste this code into your favorite sandbox:
import { tw } from 'https://cdn.skypack.dev/twind'
document.body.innerHTML = `
<main class="${tw`h-screen bg-purple-400 flex items-center justify-center`}">
<h1 class="${tw`font-bold text(center 5xl white sm:gray-800 md:pink-700)`}">This is Twind!</h1>
</main>
`
Alternatively try the ๐ live and interactive demo and take a look at the installation guide.
For seamless integration with existing Tailwind HTML you can use twind/shim:
<script type="module" src="https://cdn.skypack.dev/twind/shim"></script>
<main class="h-screen bg-purple-400 flex items-center justify-center">
<h1 class="font-bold text(center 5xl white sm:gray-800 md:pink-700)">This is Twind!</h1>
</main>
Try twind/shim
in the ๐ live and interactive shim demo
๐ For more detailed instruction on usage please read the documentation and check out this extended demo
๐ก You can click on each summary to show additional details.
In fact, there is no dependency on Tailwind or PostCSS at all. This makes it possible to use Twind without a development server. The various ways how to start using twind are described in the installation guide.
import { tw } from 'twind'
document.body.innerHTML = `
<main class="${tw`h-screen bg-purple-400 flex items-center justify-center`}">
<h1 class="${tw`font-bold text(center 5xl white sm:gray-800 md:pink-700)`}">
This is Twind!
</h1>
</main>
`
It might not always be desirable to generate rules by invoking the compiler directly via function call. In this case you may use the shim module which finds and replaces class names within HTML, generating styles appropriately. This feature can be used together with your favorite framework without any additional setup. This is especially useful during development too; for example when editing classes in the inspector.
<script type="module" src="https://cdn.skypack.dev/twind/shim"></script>
<main class="h-screen bg-purple-400 flex items-center justify-center">
<h1 class="font-bold text(center 5xl white sm:gray-800 md:pink-700)">This is Twind!</h1>
</main>
By shipping the compiler (rather than the resultant output) there is a known and fixed cost associated with styling. No matter how many styles you write or how many variants you use, all that your users will ever have to download is approximately 12KB of code (which is less than styled-components or your average purged Tailwind build).
๐ก The following list is just an excerpt. Please take a look at the Tailwind Extensions documentation page.
Custom syntax for grouping directives and variants
Having control over the interpreter affords us the possibility of defining terse syntax for grouping responsive and pseudo variants as well as directives with common prefixes. This massively reduces repetition and improves comprehension.
// Before directive grouping
tw`border-2 border-black border-opacity-50 border-dashed`
// After directive grouping
tw`border(2 black opacity-50 dashed)`
// With variants
tw`sm:(border(2 black opacity-50 hover:dashed))`
// => sm:border-2 sm:border-black sm:border-opacity-50 sm:hover:border-dashed
tw`w(1/2 sm:1/3 lg:1/6) p-2`
// => w-1/2 sm:w-1/3 lg:w-1/6 p-2
Every variant can be applied to every directive
Because twind is generating CSS during runtime there is no restriction to which directives variants can be applied.
Most pseudo classes can be used as variant or group-*
variant
Unknown variants (not listed in core variants) are assumed to be pseudo classes.
Named groups to support nested groups
Named groups allow to nest groups within each other and target specific groups by their name. The group names are ad-hoc meaning there is no special configuration required.
Here is an example using the shim:
<div class="group-x bg-white hover:bg-blue-500 ...">
<p class="text-gray-900 group-x-hover:text-white ...">New Project</p>
<div class="group-y bg-gray-100 hover:bg-green-500 ...">
<p class="text-gray-500 group-y-hover:text-white ...">
Create a new project from a variety of starting templates.
</p>
</div>
</div>
Pseudo Elements are supported using double colon
<p class="first-line::(uppercase text-blue-500)">
Styles will only be applied to the first line of this paragraph. After that, all text will be
styled like normal. See what I mean?
</p>
siblings
, sibling
and children
variants
Allows to apply styling to different elements instead of repeating a directive on each one. This feature can be combined with other variants like hover
.
override
variant to increase the specificity of rules
This can be used to ensure a rule has a higher specificity than others:
const shared = tw`text(xl center blue-600) underline`
const special = tw`${shared} override:(text-purple-600 no-underline)`
Using exclamation point (!
) after a directive to override any other declarations
Directives may end with exclamation point (text-center!
) to be marked as important
Dark mode is always available
Please see Installation - Dark Mode for details.
The base reset provided by Tailwind is instantiated with respect to your theme (values like fonts, colors etc.) and injected in the stylesheet during setup. This guarantees more consistent cross browser results out of the box.
๐ก It is possible to customize or disable the preflight.
Theming is done exactly as documented by the Tailwind meaning that you can copy paste in your themes from existing projects. The only different here is that there is no need to rebuild anything after changing you theme. Just refresh the page!
๐ก For further details please read the theme guide.
The compiler accepts functions that can return arbitrary CSS-in-JS objects. A convenient escape hatch for all those one-off rules which aren't supported by Tailwind. The &
keyword allows you to write complex rules (like pseudo elements &::before
and &::after
) that are beyond the scope of inline styles without having to add another dependency.
๐ก We provide a css helper as a convenience for this case.
Input is not limited to strings like with HTML classes. The tw
function accept arrays, objects, template literals, functions, almost everything! The interpreter spec is inspired by and is very similar to clsx and offers a much more developer friendly API that handles null values gracefully.
Using template literals as input (the recommended method) or even object syntax allows you to break rules over multiple lines, drastically improving readability and maintainability of complex rules.
By default no hashing is enabled to aid debugging during development. However it is possible to configure Twind to hash class names before injecting them into the DOM. This may be useful in production as it can reduce the down-the-wire size of server-side rendered pages and eliminates any chance of class name conflicts with third party styles.
Given the limited grammar that the compiler has to support there is a much higher chance of finding a rule and its variant in the cache. Because of this along with some other specialist optimizations we are able to compile and inject CSS faster than most CSS-in-JS solutions.
Extending the grammar is trivial and can be achieved by providing functions inline or by generalizing inline rules and defining them during setup under the plugins key.
The compiler itself is not reliant on the DOM at all which makes it an ideal candidate for static extraction which essentially removes all runtime overhead. This is possible during SSR or build time prepass.
This project was started by the authors of two similar libraries โ oceanwind and beamwind โ who chose to collaborate rather than compete with each other in this space.
Combining efforts has saved us time and resulted in a much more complete and production ready offering.
Furthermore we were able to agree on and coin some standards for certain aspects of the implementation based on our collective learnings; things like parsing input, grouping syntax, precedence calculation and plugin API.
A lot of developers ask "Why not just use Tailwind?" and our answer is always that you should use Tailwind, it is an absolutely incredible API with amazing documentation!
I've wanted to do a CSS-in-JS flavor of Tailwind for over 2 years because of all the neat benefits you get there so it's cool to see projects like this! โ @adamwathan
However, if like us you are already building your app in JS using a framework like React, Preact, Vue or Svelte, rather than just static HTML, then compiling Tailwind shorthands just in time (like twind does) rather than ahead of time like with Tailwind and PostCSS, comes with a lot of advantages.
The core problems we are trying to solve here are as follows:
This has to happen in a performant way at runtime, whilst adhering to Tailwind V2 as a language specification. All grammars that exist in Tailwind should be covered by this implementation.
Simply recreating a tailwind like experience at runtime might seem like a futile exercise but we'd like to believe it opens up the doors to some exciting new possibilities. There is always going to be a tradeoff between compiling at ahead of time and compiling just in time, however we are confident the upsides here are significant enough to persue a runtime implementation and the results have been promising so far.
Note it is still possible to remove all runtime overhead via a prepass either at serve or built time
The flexible nature of a runtime first approach affords us possibilities like:
Another big advantage we see of shipping the interpreter compiler itself (rather than pre-compiled output) is that the effective size of the CSS for your whole app is deterministic and fixed. The weight of the compiler itself along with your theme file is all that users will ever download, no matter how many styles you use.
Currently the compiler weighs around 12KB which is smaller than styled-components and the average tailwind output.
It goes without saying that the primary inspiration here comes from Tailwind. It is a revolutionary take on styling the web which has proven popular by designers and developers alike. All the core plugins here, abide by the rules painstakingly thought out, implemented and popularized by Adam Wathan et al. making us forever in his debt.
We hope one day we will get the chance to collaborate with Tailwind Labs to create an official implementation!
The implementation is tested for speed alongside several popular CSS-in-JS solutions that export general CSS functions. For those that only support a styled component approach an equivalent test has been setup. Currently Twind comes in on second place behind goober โ a less than 1KB css-in-js solution by Cristian Bote โ an awesome library worth checking out.
goober@2.0.30 x 632,419 ops/sec ยฑ0.59% (95 runs sampled)
twind (tw) x 400,438 ops/sec ยฑ0.35% (84 runs sampled)
twind (apply) x 342,725 ops/sec ยฑ0.37% (96 runs sampled)
twind (css) x 270,020 ops/sec ยฑ0.53% (95 runs sampled)
emotion@11.1.3 x 229,990 ops/sec ยฑ0.17% (99 runs sampled)
goober@2.0.30 x 842,430 ops/sec ยฑ1.10% (88 runs sampled)
twind (css) x 203,990 ops/sec ยฑ0.32% (94 runs sampled)
emotion@11.1.3 x 162,460 ops/sec ยฑ0.75% (90 runs sampled)
otion@0.6.2 x 53,592 ops/sec ยฑ0.85% (96 runs sampled)
twind x 51,628 ops/sec ยฑ0.63% (89 runs sampled)
goober@2.0.18 x 40,069 ops/sec ยฑ0.43% (96 runs sampled)
emotion@11.0.0 x 35,349 ops/sec ยฑ1.01% (93 runs sampled)
styled-components@5.2.1 x 38,284 ops/sec ยฑ0.48% (93 runs sampled)
For a more detailed testing summary please see the benchmarks directory.
It would be untrue to suggest that the design here is totally original. Other than the founders' initial attempts at implementing such a module (oceanwind and beamwind) we are truly standing on the shoulders of giants.
FAQs
compiles tailwind like shorthand syntax into css at runtime
The npm package twind receives a total of 4,235 weekly downloads. As such, twind popularity was classified as popular.
We found that twind demonstrated a not healthy version release cadence and project activity because the last version was released a year ago.ย It has 2 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
GitHub removed 27 malicious pull requests attempting to inject harmful code across multiple open source repositories, in another round of low-effort attacks.
Security News
RubyGems.org has added a new "maintainer" role that allows for publishing new versions of gems. This new permission type is aimed at improving security for gem owners and the service overall.
Security News
Node.js will be enforcing stricter semver-major PR policies a month before major releases to enhance stability and ensure reliable release candidates.