Skip to content

Migrate from Tailwind

Planning to migrate from Tailwind CSS to WovenUI? This guide maps Tailwind utilities and component classes to WovenUI core and the kit.

This page is for teams that style with Tailwind utilities and add a component layer on top, such as daisyUI, Flowbite, Tailwind UI or shadcn style components, and want ready-made HTML and CSS components on a token system. Utilities and components come from two packages: WovenUI core has the utility classes and apply() mixins, and @wovenui/components has the components. Install the kit from the install page. For the framework-level comparison, read WovenUI vs Tailwind CSS.

In core the utility comes first and the modifier follows it: a breakpoint is a suffix (p-4@lg), a state is a prefix on the class (hover:bg-brand-subtle). Flex modifiers apply on a flex element, so write class="flex between x-center". The breakpoint names and sizes (md, lg) are core defaults, set by the $breakpoints setting; see the configuration page.

Tailwind WovenUI core Notes
flex justify-between flex between Main axis, no prefix
items-center x-center x- is the cross axis
items-start x-start On a flex element
flex-col col On a flex element
flex-1 grow On a child of a flex element
shrink-0 no-shrink On a child of a flex element
lg:p-4 p-4@lg Mobile first, from the breakpoint up
md:flex-row row@md Same suffix for every utility
hover:bg-blue-50 hover:bg-brand-subtle State prefix on the class; also hover:opacity-75, hover:shadow-md
bg-white bg-surface Follows the theme
text-gray-600 text-muted Semantic word, not a shade
border-gray-200 border-regular Or plain border for the width
ml-4, mr-4 ms-4, me-4 Logical, so they flip in right to left
text-left text-start Logical
z-50 z-modal Named levels
space-x-4 space-x-4 Same name, logical
dark:bg-gray-800 bg-surface No dark: class, see below
top-[117px] top(117px) in SCSS Custom values live in SCSS

Anything else with a state goes through apply(), for example bg(brand-hover) hover.

Every utility is also a mixin. A Tailwind @apply line turns into one apply() call, with the modifier after the item:

@use "@wovenui/core" as *;
// Tailwind: @apply flex justify-between items-center p-4 bg-white rounded-lg hover:shadow-md lg:p-8;
.toolbar {
@include apply(flex, between, x-center, p(4), bg(surface), rounded(lg), shadow(md) hover, p(8) lg);
}

A unitless number is a scale key (p(4) is 1rem). A value with a unit is used as written (p(13px)). A wrong key stops the compile and the message lists the valid ones. Read more in Utility classes, apply(), Responsive and Flex.

There are no dark: classes. Semantic classes such as bg-surface and text-muted read tokens, and the tokens switch with data-theme on any element:

<html data-theme="dark">
<body class="bg-base text-regular">
<aside data-theme="light" class="bg-surface p-4">A light panel in a dark page</aside>
</body>
</html>

Without data-theme the operating system decides. See Theming.

Tailwind has no components of its own. The left column shows daisyUI markup, a common component layer; Flowbite and similar libraries use other class names for the same parts. The kit uses a wu- root and bare words for variants, valid only together with the root: wu-btn brand sm. Colors use the core role names, so primary becomes brand.

daisyUI WovenUI Components Notes
<button class="btn btn-primary"> <button class="wu-btn brand"> On a <button> or a link
<button class="btn btn-error"> <button class="wu-btn danger"> Destructive actions
<button class="btn"> <button class="wu-btn"> The plain button is the neutral one
<button class="btn btn-outline"> <button class="wu-btn brand subtle"> A tinted outline; the plain wu-btn is outlined too
<button class="btn btn-ghost"> <button class="wu-btn quiet"> Transparent until hover
btn-sm, btn-lg sm, lg wu-btn brand sm
<div class="badge badge-success"> <span class="wu-badge success"> Add solid for a filled badge
<div class="card"> <article class="wu-card"> Parts: <header class="wu-card-header">, <div class="wu-card-body">, <footer class="wu-card-footer">; heading in wu-card-title
<dialog class="modal"> <dialog class="wu-modal"> Opened with commandfor and command="show-modal", no script
<div class="modal-action"> <form class="wu-modal-footer"> A <form method="dialog">
<details class="dropdown"> <div class="wu-dropdown" popover> Items are wu-dropdown-item links or buttons; opened with popovertarget, no script
<div role="tablist" class="tabs"> <div class="wu-tabs"> Parts wu-tabs-list, wu-tabs-tab, wu-tabs-panel; active tab is aria-selected="true"; the kit script adds the keyboard
<input type="checkbox" class="toggle"> <label class="wu-toggle"> Wraps <input class="wu-toggle-input" role="switch">
<input class="input"> <input class="wu-input"> On a text-like <input>; core already styles the border
<select class="select"> <select class="wu-select"> On a native <select>
<input type="checkbox" class="checkbox"> <label class="wu-checkbox"> Wraps <input class="wu-checkbox-input">
<input type="radio" class="radio"> <label class="wu-radio"> Wraps <input class="wu-radio-input">, like the checkbox
<div role="alert" class="alert alert-success"> <div class="wu-alert success"> Title in wu-alert-title
<div class="toast"> toast() from the kit script, or <div class="wu-toast"> Shown in a polite live region
<table class="table table-zebra"> <table class="wu-table striped"> Also hover, bordered, sm
<div class="drawer"> <dialog class="wu-drawer"> Inline end by default
<div class="collapse"> <div class="wu-accordion"> Each item is <details class="wu-accordion-item">; no script
<span class="loading loading-spinner"> <span class="wu-spinner"> Pair with role="status" and hidden text
<progress class="progress"> <progress class="wu-progress"> On a native <progress>
<div class="breadcrumbs"> <nav class="wu-breadcrumb"> Wraps <ol class="wu-breadcrumb-list">
<div class="tooltip" data-tip="..."> data-tooltip Lives in core, see tooltips

Layout around the components still uses core utilities, so a card grid is grid and gap-4 from the first table, not a kit class.

Tailwind gives you no modal or dropdown, so most teams add a script library or write the open and close code themselves. The kit gives you these without writing any JavaScript: a modal and drawer on <dialog>, a dropdown and popover on the popover attribute, and an accordion on <details>.

  • No class scanning. WovenUI does not read your source files to decide what CSS to generate. Utility classes are off by default in the Sass entry, so you ship tokens, base styles and the rules you write, and a component stylesheet adds only its own rules. The kit is compiled CSS: load the bundle, or per-component entries to load only what you use. See WovenUI vs Tailwind CSS for the details.
  • Tokens and themes. Every component reads core --wu-* tokens, so light, dark, inverse and high contrast need no extra classes and no per-color dark: pairs.
  • Native elements. Modals and drawers are <dialog>, menus and popovers use the popover attribute, and accordions are <details>. The browser handles focus, Esc and the top layer, so most components need no JavaScript.
  • No icon set. The kit ships no icons. Markers such as the select arrow and the close cross are drawn in CSS. Bring the icon set you already use.
  • Right to left. Components use logical properties, so one stylesheet serves both directions. See Right to left.
  • Motion is opt-in. Components are calm by default. Add animated (or wu-animated on an ancestor) to turn motion on; it still respects prefers-reduced-motion.
  1. Install the kit. Load the bundle or per-component entries, not both.
  2. Replace layout and helper classes with core utilities, using the first table.
  3. Swap components one at a time with the component table. Keep the old CSS loaded until the last one is gone.
  4. Move colors and spacing to core tokens, and switch themes with data-theme.
  5. Remove the old framework’s CSS and script.