--- url: /docs/about.md --- # About Winduum is a mix of words **Tailwind** *(Popular CSS utility framework)* and **Tuum** *(Estonian word for "core")*. It essentially provides ways to leverage use of **modern and accessible standards** as much possible. Because we ❤️ CSS and this is a small modest CSS component framework. Its approach to **TailwindCSS** is a little different. It encourages writing components in CSS or other (pre/post)-processors and to use utility classes to enhance the components. As a CSS library, it provides beautifully styled accessible components. Which you can extend with your own components. It is very modular and split to `base`, `components` and `utilities` layers. You can choose what you want to use and make your own complex UX/UI project written in whatever you want. ## Why? The question inevitably arises: Why introduce yet another UI component library into the mix? Simply because Winduum is different in a few areas than the others. 1. It focuses on web standards, accessibility and minimum simple code 2. It's progressive, uses modern features and standards 3. It's framework-agnostic, so it can be used in any scenario 4. Its source code is plain CSS and JS, so it can be also used without a build step ## Framework-agnostic Winduum is **framework-agnostic**, so you are able to create your own components using your preferred framework. Javascript primitives can be also adapted in any framework. If there is interest, pre-built components may be developed for popular frameworks. Currently, only [`winduum-vue`](https://www.github.com/winduum/winduum-vue) and [`winduum-react`](https://www.github.com/winduum/winduum-react) are available and most of the components have usage and installation examples in the docs. Want to help? We're open for pull requests! ## Modern CSS Features Staying ahead of the curve, Winduum leverages modern CSS features, allowing you to harness the power of the latest specifications and improve overall styling capabilities. All of these are supported in current browsers. * **CSS Properties** * **CSS Logical Properties** * **CSS Nesting** * **CSS color-mix** * **Modern pseudo selectors** such as `:where`, `:is` and `:has` * **Modern CSS reset** * **View Transition API, Dialog API, Popover API** and more! * **Low specifity or layers** **Winduum** is all about accessibility and web standards that can be used in any framework. ## Naming In your projects it's recommended to prefix component classes for better clarity. Some of these are already used for various components. * **Component** - `x-name` (with prefix, every component is prefixed) * **Utilities** - `name` (without prefix, utility classes for common styles) ## CSS Properties Each CSS property follows the same naming, for example `--x-name-font-size` ## Directory structure To help navigate your project easily, it's recommended to follow the same naming principles for your directory structure, for example, like this: * 📁 **base** * 📁 **components** * 📁 **theme** * 📁 **utilities** or **utils** ## Examples ### Using the components You can use any of the components easily in HTML without the need to write complex TailwindCSS classes. Each component is written with low specificity in mind, so any property can be easily enhanced with TailwindCSS utility classes. ::: code-group ```html ``` ```css .x-button { --x-button-font-size: 0.875rem; /* CSS styles */ } ``` ::: ### Writing the components You can write your own components using the same approach ::: code-group ```html
Hello world
``` ```css .x-hello-world { --x-hello-world-font-size: 2rem; /* CSS styles */ } ``` ::: It's recommended to use TailwindCSS utility classes for most cases. If you want to style some elements in CSS inside the component, consider creating a new component. If you don't want to create a new component, don't use complex conventions like BEM. It's recommended to use something like [part](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/part) attribute. For example `data-part="body"` ```css .x-hello-world { :where([data-part~"body"]) { /* CSS styles */ } } ``` This way you can tell that it's an element related to the parent component. In rare cases you want to prevent possible class conflicts you can add name of the component inside the class like this `x-hello-world:body`. --- --- url: /docs/utilities/accent.md --- # Accent Provides a new TailwindCSS utility class `accent` which extends [Accent](https://tailwindcss.com/docs/accent) utility classe. ## TailwindCSS v4 Include CSS file with the `@utility` at-rule. ```css @import "winduum/tailwindcss/utilities/accent.css"; ``` ## TailwindCSS v3 Add plugin via the `tailwind.config.js`, see [Config](/docs/base/config#tailwind-css-v3) for more info. ## Example ```html
``` --- --- url: /docs/utilities/animation.md --- # Animation Provides a new utility class `animation` and TailwindCSS utility class `animation-*` for `animation-name` property. You should use this together with [Keyframes](/docs/base/keyframes) or use your own animation keyframes. ### Dependencies * [tailwindcss](https://tailwindcss.com/) (TailwindCSS v4 @utility) * [winduum](/docs/base/config.html#tailwind-css-v3) (TailwindCSS v3 plugin) ## TailwindCSS v4 You can add more via the `@theme` at-rule, see [Config](/docs/base/config#tailwind-css-v4) for more info. Include CSS file with the `@utility` at-rule. ```css @import "winduum/tailwindcss/utilities/animation.css"; ``` ### Example ```css @theme { --animation-fade-in: fade-in; } ``` ```html
Content
``` ```css .animation { animation-duration: var(--default-animation-duration, var(--default-transition-duration)); animation-fill-mode: both; } .animation-fade-in { animation-name: var(--animation-fade-in); } ``` or use arbitrary value ```html
Content
``` ```css .animation { animation-duration: var(--default-animation-duration, var(--default-transition-duration)); animation-fill-mode: both; } .animation-fade-in { animation-name: fade-in; } ``` ## TailwindCSS v3 You can add more via the `tailwind.config.js`, see [Config](/docs/base/config#tailwind-css-v3) for more info. ### Example ```html
Content
``` ```css .animation { animation-duration: var(--default-animation-duration, var(--default-transition-duration)); animation-fill-mode: both; } .animation-fade-in { animation-name: fade-in; } ``` --- --- url: /docs/components/badge.md --- # Badge ### Usage ```css @import "winduum/src/components/badge/index.css" layer(utilities); ``` ### Variants ### Props ### Tokens * `bordered` * `muted` * `sm` * `lg` * `square` * `circle` ### Installation Follow instructions for individual framework usage below ## Examples ### Basic ```html \[html]
Badge
Badge
``` ```vue ``` ```jsx import { Badge } from "@/components/badge" export function Example() { return ( <> Badge Badge ) } ``` ::: ### Flat ```html
Primary
Main
Success
Error
Warning
Info
Dark
Light
``` ### Bordered ```html
Primary
Main
Success
Error
Warning
Info
Dark
Light
``` ### Muted ```html
Primary
Main
Success
Error
Warning
Info
Dark
Light
``` ### Small ```html
Badge
``` ### Large ```html
Badge
``` ### Square ```html
1
2
``` ### Circle ```html
1
2
``` ### Icon ```html
Badge
Badge
``` ### Custom ```css .x-badge { --x-badge-block-size: 1rem; --x-badge-padding-block: 0; --x-badge-padding-inline: 1rem; --x-badge-border-radius: 0; --x-badge-font-size: 0.75rem; --x-badge-font-weight: 700; --x-badge-background-color: yellow; --x-badge-color: #333; } ``` You can also extend the badge with any TailwindCSS class to customize it ```html ``` ### Group You can group badges into groups via `x-group` component. ```html
Badge
Badge
Badge
Badge
Badge
Badge
Badge
Badge
Badge
npm
7.1.2
``` --- --- url: /docs/components/breadcrumb.md --- # Breadcrumb ### Usage ```css @import "winduum/src/components/breadcrumb/index.css" layer(utilities); ``` ### Variants ### Props ### Installation Follow instructions for individual framework usage below ## Example ```html ``` --- --- url: /docs/base/breakpoints.md --- # Breakpoints Breakpoints in Winduum are very close to TailwindCSS, yet they have slightly different values and extended to cover all possible resolutions. You can use the same principles as defined in [Responsive design](https://tailwindcss.com/docs/responsive-design) * **xs** - 360px * **sm** - 416px * **md** - 744px * **lg** - 960px * **xl** - 1216px * **2xl** - 1312px * **3xl** - 1408px * **4xl** - 1600px * **xxl** - 2016px * **2xxl** - 2528px Breakpoints are defined in [`src/base/breakpoints.css`](https://github.com/winduum/winduum/blob/main/src/base/breakpoints.css) and in [config#screens](/docs/base/config#screens) (TailwindCSS `v3`) or [`tailwindcss/theme/config/breakpoint.css`](https://github.com/winduum/winduum/blob/main/tailwindcss/theme/config/breakpoint.css) (TailwindCSS `v4`) You can also use the breakpoints inside CSS like this. ```postcss @media (--media-md) { /* > 768 */ } @media not all and (--media-md) { /* < 768 */ } ``` [Custom Media Specification](https://www.w3.org/TR/mediaqueries-5/#at-ruledef-custom-media) is used, so PostCSS or LightningCSS is required, see [Install](/docs/) for more info. --- --- url: /docs/components/button.md --- # Button ### Usage ```css @import "winduum/src/components/button/index.css" layer(utilities); ``` ### Variants ### Props ### Tokens * `bordered` * `muted` * `raised` * `ghosted` * `sm` * `lg` * `square` * `circle` * `fill` ### Installation Follow instructions for individual framework usage below ## Examples ### Basic ```html \[html] ``` ```vue ``` ```jsx import { Button } from "@/components/button" export function Example() { return ( <> ) } ``` ::: ### Flat ```html ``` ### Bordered ```html ``` ### Muted ```html ``` ### Raised ```html ``` ### Ghosted ```html ``` ### Small ```html ``` ### Large ```html ``` ### Square ```html ``` ### Circle ```html ``` ### Icon ```html ``` ### Loading ```html ``` ### Active ```html ``` ### Disabled ```html ``` ### Custom ```html ``` ```css .x-custom { --color-accent: yellow; --color-accent-foreground: #333; --x-button-block-size: 4rem; --x-button-padding-block: 1rem; --x-button-padding-inline: 1rem; --x-button-border-radius: 0; --x-button-font-size: 1.15rem; --x-button-font-weight: 700; --x-button-hover-opacity: 40%; --x-button-focus-opacity: 80%; } ``` You can also extend the button with any TailwindCSS class to customize it ```html ``` ### Group You can group buttons into groups via `x-group` component. ```html
``` ## Custom Props ### default | CSS property | Default value | |---------------------------------------|----------------------------------| | `--x-button-inline-size` | `initial` | | `--x-button-block-size` | `2.25rem` | | `--x-button-padding-block` | `0.375rem` | | `--x-button-padding-inline` | `0.75rem` | | `--x-button-border-radius` | `var(--radius, 0.75rem)` | | `--x-button-font-family` | `initial` | | `--x-button-font-size` | `var(--font-size-sm, 0.875rem)` | | `--x-button-font-weight` | `var(--font-weight-medium, 500)` | | `--x-button-letter-spacing` | `initial` | | `--x-button-background-color-space` | `srgb` | | `--x-button-background-color` | `var(--color-accent)` | | `--x-button-background-color-opacity` | `100%` | | `--x-button-background-color-mix` | `transparent` | | `--x-button-color-space` | `srgb` | | `--x-button-color` | `var(--color-accent-foreground)` | | `--x-button-color-opacity` | `100%` | | `--x-button-color-mix` | `transparent` | | `--x-button-border-width` | `0px` | | `--x-button-border-color-space` | `srgb` | | `--x-button-border-color` | `var(--color-accent)` | | `--x-button-border-color-opacity` | `100%` | | `--x-button-border-color-mix` | `transparent` | | `--x-button-outline-width` | `2px` | | `--x-button-outline-color-space` | `srgb` | | `--x-button-outline-color` | `transparent` | | `--x-button-outline-color-opacity` | `100%` | | `--x-button-outline-color-mix` | `transparent` | | `--x-button-outline-offset` | `initial` | | `--x-button-gap` | `var(--spacing-2, 0.5rem)` | ### interactive | CSS property | Default value | |------------------------------------------------|--------------------------------------------| | `--x-button-transition-property` | `var(--default-transition-property)` | | `--x-button-timing-function` | `var(--transition-timing-function-in-out)` | | `--x-button-transition-duration` | `var(--default-transition-duration)` | | `--x-button-hover-background-color` | `var(--color-accent)` | | `--x-button-hover-background-color-mix` | `var(--color-dark)` | | `--x-button-hover-background-color-opacity` | `80%` | | `--x-button-hover-border-color` | `var(--color-accent)` | | `--x-button-hover-border-color-mix` | `transparent` | | `--x-button-hover-border-color-opacity` | `100%` | | `--x-button-hover-color` | `var(--color-accent-foreground)` | | `--x-button-hover-color-mix` | `transparent` | | `--x-button-hover-color-opacity` | `100%` | | `--x-button-focus-outline-offset` | `2px` | | `--x-button-focus-outline-color` | `var(--color-accent)` | | `--x-button-focus-outline-color-opacity` | `50%` | | `--x-button-active-background-color` | `var(--color-accent)` | | `--x-button-active-background-color-mix` | `var(--color-dark)` | | `--x-button-active-background-color-opacity` | `90%` | | `--x-button-active-border-color` | `var(--color-accent)` | | `--x-button-active-border-color-mix` | `transparent` | | `--x-button-active-border-color-opacity` | `100%` | | `--x-button-active-color` | `var(--color-accent-foreground)` | | `--x-button-active-color-mix` | `transparent` | | `--x-button-active-color-opacity` | `100%` | | `--x-button-disabled-background-color` | `var(--color-accent)` | | `--x-button-disabled-background-color-mix` | `transparent` | | `--x-button-disabled-background-color-opacity` | `50%` | | `--x-button-disabled-border-color` | `var(--color-accent)` | | `--x-button-disabled-border-color-mix` | `transparent` | | `--x-button-disabled-border-color-opacity` | `50%` | | `--x-button-disabled-color` | `var(--color-accent-foreground)` | | `--x-button-disabled-color-mix` | `transparent` | | `--x-button-disabled-color-opacity` | `50%` | --- --- url: /docs/components/card.md --- # Card ### Usage ```css @import "winduum/src/components/card/index.css" layer(utilities); ``` ### Variants ### Props ### Installation Follow instructions for individual framework usage below ## Examples ### Default ```html
Card title
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nulla accumsan, elit sit amet varius semper, nulla mauris mollis quam, tempor suscipit diam nulla vel leo. Lorem ipsum dolor sit amet
``` ### Image ```html
Card title
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nulla accumsan, elit sit amet varius semper, nulla mauris mollis quam, tempor suscipit diam nulla vel leo. Lorem ipsum dolor sit amet
``` --- --- url: /docs/components/carousel.md --- # Carousel Provides a scroll carousel that uses native CSS `scroll-snap` property. ### Usage ::: code-group ```css @import "winduum/src/components/carousel/index.css" layer(utilities); ``` ```liquid \[js] ``` ### Variants ### Installation Follow instructions for individual framework usage below ## Examples ### Basic ```liquid \[js] ``` ### Full ```liquid \[js] ``` ## Javascript API ### `scrollTo` * **Type:** `(element: HTMLElement | Element, index: number) => void` * **Kind:** `sync` Scroll to a snap item by its index. ### `scrollNext` * **Type:** `(element: HTMLElement | Element) => void` * **Kind:** `sync` Scroll to the next snap item. ### `scrollPrev` * **Type:** `(element: HTMLElement | Element) => void` * **Kind:** `sync` Scroll to a previous snap item. ### `getItemCount` * **Type:** `(element: HTMLElement | Element, scrollWidth: number, mathFloor: boolean) => number` * **Kind:** `sync` Get the number of possible scrolls inside the carousel. ### `observeCarousel` * **Type:** `(element: HTMLElement | Element, options?: ObserveCarouselOptions) => void` * **Kind:** `sync` Adds an observer for the carousel. Adds properties `_observer` and `_activeIndex` to the DOM of the carousel `element`. #### ObserveCarouselOptions *** ##### visibleAttribute * **Type:** `string` * **Default:** `data-visible` A class that is added to the carousel items once they are visible. *** ##### observerOptions * **Type:** `IntersectionObserverInit` * **Default:** `{ threshold: 0.5 }` Additional [options](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver/IntersectionObserver#options) confugration for the observer. *** ### `dragCarousel` * **Type:** `(element: HTMLElement | Element, options?: DragCarouselOptions) => void` * **Kind:** `sync` Adds a mouse dragging capability to the carousel. #### DragCarouselOptions *** ##### activeAttribute * **Type:** `string` * **Default:** `data-grabbing` *** ### `paginationCarousel` * **Type:** `(element: HTMLElement | Element, options?: PaginationCarouselOptions) => void` * **Kind:** `sync` Inserts pagination indicators for the carousel to the desired element. #### PaginationCarouselOptions *** ##### element * **Type:** `HTMLElement | Element` * **Default:** `undefined` *** ##### itemContent * **Type:** `string` * **Default:** `` *** ##### activeAttribute * **Type:** `string` * **Default:** `data-active` *** ### `autoplayCarousel` * **Type:** `(element: HTMLElement | Element, options?: AutoplayCarouselOptions) => void` * **Kind:** `sync` Adds an autoplay for the carousel. #### AutoplayCarouselOptions *** ##### delay * **Type:** `number` * **Default:** `4000` Delay in ms. *** ##### pauseElements * **Type:** `HTMLElement[] | Element[]` * **Default:** `[]` Which elements should pause the autoplay upon hover. *** ### `scrollCarousel` * **Type:** `(element: HTMLElement | Element, options?: ScrollCarouselOptions) => void` * **Kind:** `sync` A helper function that updates various carousel states upon scroll. #### ScrollCarouselOptions *** ##### observe * **Type:** `ObserveCarouselOptions` * **Default:** `undefined` *** ##### pagination * **Type:** `PaginationCarouselOptions` * **Default:** `{ activeClass: 'active' }` *** ##### progressElement * **Type:** `HTMLProgressElement | Element` * **Default:** `undefined` *** ##### counterMinElement * **Type:** `HTMLElement | Element` * **Default:** `undefined` *** ##### counterMaxElement * **Type:** `HTMLElement | Element` * **Default:** `undefined` --- --- url: /docs/components/check.md --- # Check Check supports `checkbox` and `radio` **input** types ### Usage ```css @import "winduum/src/components/check/index.css" layer(utilities); ``` ### Variants ### Props ### Installation Follow instructions for individual framework usage below ## Examples ### Basic ```html \[html]
Checkbox
``` ```vue ``` ```jsx import { Check } from "@/components/check" export function Example() { return ( <> Checkbox ) } ``` ::: ```html \[html]
Radio
``` ```vue ``` ```jsx import { UiCheck } from "@/components/check" export function Example() { return ( <> Radio ) } ``` ::: ### Label ```html
``` ```html
``` ### Required ```html
``` ```html
``` ### Disabled ```html
Checkbox
``` ```html
Radio
``` ### Validation ```html
``` ```html
``` --- --- url: /docs/components/color.md --- # Color Color supports `checkbox` and `radio` **input** types for displaying selected color. ### Usage ```css @import "winduum/src/components/color/index.css" layer(utilities); ``` ### Variants ### Props ### Installation Follow instructions for individual framework usage below ## Examples ### Basic ```html \[html] ``` ```vue ``` ```jsx import { Color } from "@/components/color" export function Example() { return ( <> ) } ``` ::: ### Disabled ```html ``` --- --- url: /docs/colors.md --- # Colors There are few types of colors with various areas of use. Colors are defined in [Theme](/docs/base/theme). ## Common ## Main ## Body ## State ## Foreground Each color has also it's foreground variant with `-foreground` postfix. So you can use foreground colors when needed, eg. `--color-primary-foreground`. ## Accent The idea is that you should be able to set accent color via `accent-color` CSS property. It is [discussed](https://github.com/w3c/csswg-drafts/issues/5900) that you should have access to the color value of this property, e.g. via `AccentColor` or `AccentColorText`. Most of the components are using this idea via `--color-accent` and `--color-accent-foreground` as an alternative for their accent color. ```html
``` For example, this way you don't have to change background-color property for each component color variant, you just change the accent color. --- --- url: /docs/components/compare.md --- # Compare Side-by-side comparison slider component. ### Usage ```css @import "winduum/src/components/compare/index.css" layer(utilities); ``` ### Variants ### Installation Follow instructions for individual framework usage below ## Examples ### Default ```liquid \[js] ``` ### Text ```liquid \[js] ``` ## Javascript API ### setPosition * **Type:** `(element: HTMLInputElement, options?: SetPositionOptions) => void` * **Kind:** `sync` #### SetPositionOptions *** ##### selector * **Type:** `string` * **Default:** `.x-compare` *** ##### positionProperty * **Type:** `string` * **Default:** `--x-compare-position` *** ### setKeyboardStep * **Type:** `(element: HTMLInputElement, key: string, step?: number) => void` * **Kind:** `sync` ### setMouseStep * **Type:** `(element: HTMLInputElement, step?: number) => void` * **Kind:** `sync` --- --- url: /docs/utilities/container.md --- # Container Provides a new approach to classic [Container](https://tailwindcss.com/docs/container) with a new utility class `grid-cols-container` which utilizes `grid` and is inspired by [Kevin Powell](https://youtu.be/c13gpBrnGEw?si=FGoMS9FnWEOYohPi). ```css .grid-cols-container { grid-template-columns: [container-full-start] minmax(var(--container-padding), 1fr) [container-breakout-start] minmax(0, calc((var(--container-breakout-width) - var(--container-width)) / 2)) [container-start] min(100% - (var(--container-padding) * 2), var(--container-width)) [container-end] minmax(0, calc((var(--container-breakout-width) - var(--container-width)) / 2)) [container-breakout-end] minmax(var(--container-padding), 1fr) [container-full-end]; & > :where(*) { grid-column: container; } } ``` ## Example Easy layout with `grid` ```html
Header Full Width
Content in container
``` In same cases classic approach is still handy, you can achieve that easily with `w` ```html
Content
``` --- --- url: /docs/components/control.md --- # Control Form control as it should be! This component supports **input**, **select** and **textarea** including **all** [input types](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input) * `text`, `color`, `date`, `datetime-local`, `email`, `file`, `hidden`, `month`, `number`, `password`, `search`, `tel`, `time`, `url`, `week` Other input types are supported in other components * `checkbox`, `radio` - included in [Check](/docs/components/check), [Switch](/docs/components/switch), [Color](/docs/components/color) or [Rating](/docs/components/rating) * `range` - included in [Range](/docs/components/range) * `button`, `reset`, `submit` - included in [Button](/docs/components/button) ### Installation Follow instructions for individual framework usage below ### Usage ```css @import "winduum/src/components/control/index.css" layer(utilities); ``` ### Variants ### Props ## Examples ### Basic ```html \[html]
``` ```vue ``` ```jsx import { Control } from "@/components/control" export function Example() { return ( <> ) } ``` ::: ### Icon You can position any content to `start` and `end` of the control.Padding is automatically handled by CSS up to two icons, or you can do it manually. * `--x-control-icon-count-start` - number of icons at the start of the control * `--x-control-icon-count-end`- number of icons at the end of the control * `--x-control-start` - manually change start padding in px according to content * `--x-control-end` - manually change end padding in px according to content ```html
EUR
``` ```html
``` ### Textarea ```html
``` ### Select ```html
``` ### Placeholder ```html
``` ### Label ```html
``` ```html
``` ### Floating Label ```html
``` ```html
``` ### Time ```html
``` ### Date ```html
``` ### Datetime ```html
``` ### Number ```html
``` ### Color ```html
``` ### File ```html
``` ### Required ```html
``` ### Validation ```html
``` ```html
``` ### Disabled ```html
``` ```html
``` ### Group You can group controls into groups via `x-group` component and combine them with other components like [Button](/docs/components/button) ```html
@
``` --- --- url: /docs/base/config.md --- # CSS config Each CSS property is defined in CSS in following path - [`src/theme/config/index.css`](https://github.com/winduum/winduum/blob/main/src/theme/config/index.css). We are using naming conventions from TailwindCSS `v4`, so you can use these properties in both current and future versions of TailwindCSS or without TailwindCSS. ```css @import "./font.css"; @import "./radius.css"; @import "./spacing.css"; @import "./transition.css"; @import "./z.css"; ``` ## Tailwind CSS v4 In the new version of TailwindCSS the configuration is done via CSS, so no plugin is necessary. Most of the config CSS properties are also part of the new version. ```css @import "tailwindcss/theme.css" layer(theme); @import "winduum/tailwindcss/theme/config/index.css" layer(theme); @import "winduum/tailwindcss/theme/default.css" layer(theme); ``` ## Tailwind CSS v3 To add `winduum` to TailwindCSS v3, add folowing plugin to `tailwind.config.js` configuration file. ```js import winduum from 'winduum' export default { darkMode: 'class', content: [ './node_modules/winduum/src/**/*.js', './src/**/*.{js,html}' ], plugins: [ winduum({ // config options }) ], } ``` You can customize config with options listed bellow. This plugin disables by default following TailwindCSS corePlugins * **preflight** - custom modern css reset is used, see [Reset](/docs/base/reset) Winduum also exports useful helper functions you can use in your `tailwind.config.js`, see [`utils/tailwind.js`](https://github.com/winduum/winduum/blob/main/utils/tailwind.js) for more info. ### settings.rgb Include `-rgb` color variants. Learn more about this in [Compatibility](/docs/base/theme.html#compatibility) section. * **Type:** `boolean` * **Default:** `false` ### settings.colorMix Use `color-mix` in color variants instead of rgb. Learn more about this in [Compatibility](/docs/base/theme.html#compatibility) section. * **Type:** `boolean` * **Default:** `true` ### colors * **Type:** `string[] | string` * **Default:** `undefined` These are additional color tokens that can be used with TailwindCSS as CSS custom properties, which can be then defined in `.css`. See [Colors](/docs/colors) for more info. Or you can add a path to `.css` file containing the CSS custom properties, and it will be parsed automatically. Example `bg-primary`: ```css .bg-primary { background-color: color-mix(in sRGB, var(--color-primary) calc(var(--tw-bg-opacity, 1) * 100%), transparent); } ``` ### fontFamily * **Type:** `string[] | string` * **Default:** `undefined` These are additional font-family tokens that can be used with TailwindCSS as CSS properties, which can be then defined in `.css`. Or you can add a path to `.css` file containing the CSS custom properties, and it will be parsed automatically. Example `font-primary`: ```css .font-primary { font-family: var(--font-primary); } ``` ### fontWeight * **Type:** `string[] | string` * **Default:** `undefined` These are additional font-weight tokens that can be used with TailwindCSS as CSS properties, which can be then defined in `.css`. Or you can add a path to `.css` file containing the CSS custom properties, and it will be parsed automatically. Example `font-bold`: ```css .font-bold { font-weight: var(--font-bold); } ``` ### ease * **Type:** `string[] | string` * **Default:** `undefined` These are additional transition easing tokens that can be used with TailwindCSS as CSS properties, which can be then defined in `.css`. Or you can add a path to `.css` file containing the CSS custom properties, and it will be parsed automatically. Example `ease-linear`: ```css .ease-linear { transition-timing-function: var(--ease-linear); } ``` ### zIndex * **Type:** `string[] | string` * **Default:** `undefined` These are additional z-index tokens that can be used with TailwindCSS as CSS properties, which can be then defined in `.css`. Or you can add a path to `.css` file containing the CSS custom properties, and it will be parsed automatically. Example `z-10`: ```css .z-10 { z-index: var(--z-10); } ``` ### fontSize * **Type:** `string[] | string` * **Default:** `undefined` These are additional `font-size` tokens that can be used with TailwindCSS as CSS properties, which can be then defined in `.css`. Or you can add a path to `.css` file containing the CSS custom properties, and it will be parsed automatically. Example `text-md`: ```css .text-md { font-size: var(--font-size-md); line-height: calc(var(--font-size-md) + 0.5rem); } ``` ### spacing * **Type:** `string[] | string` * **Default:** `undefined` These are additional spacing tokens that can be used with TailwindCSS as CSS properties, which can be then defined in `.css`. Or you can add a path to `.css` file containing the CSS custom properties, and it will be parsed automatically. Example `gap-4`: ```css .gap-4 { gap: var(--spacing-4); } ``` Example `px-4`: ```css .px-4 { padding-left: var(--spacing-4); padding-right: var(--spacing-4); } ``` ### borderRadius * **Type:** `string[] | string` * **Default:** `undefined` These are additional border-radius tokens that can be used with TailwindCSS as CSS properties, which can be then defined in `.css`. Or you can add a path to `.css` file containing the CSS custom properties, and it will be parsed automatically. Example `rounded-md`: ```css .rounded-md { border-radius: var(--radius-md); } ``` ### animations * **Type:** `string[]` * **Default:** `['fade-in', 'fade-out', 'ripple', 'spin', 'move-indeterminate']` These are additional animation tokens that can be used with TailwindCSS as CSS properties, which can be then defined in `.css`. Or you can add a path to `.css` file containing the CSS custom properties, and it will be parsed automatically. Example `animation-fade-in`: ```css .animation-fade-in { animation-name: fade-in; } ``` ### mask * **Type:** `string[] | string` * **Default:** `undefined` These are additional mask tokens that can be used with TailwindCSS as CSS properties, which can be then defined in `.css`. Or you can add a path to `.css` file containing the CSS custom properties, and it will be parsed automatically. Example `animation-fade-in`: ```css .mask-check { mask: var(--mask-check) } ``` ### screens * **Type:** `object` * **Default:** ```js { 'xs': '22.5em', 'sm': '26em', 'md': '48em', 'lg': '60em', 'xl': '76em', '2xl': '82em', '3xl': '88em', '4xl': '100em', 'xxl': '126em', '2xxl': '158em' } ``` These are new media queries tokens that can be used with TailwindCSS, see more in [Breakpoints](/docs/base/breakpoints) --- --- url: /docs/base/defaults.md --- # Defaults Default styles or rules applied to certain HTML elements or pseudo-elements. These are very much optional. [`src/base/defaults.css`](https://github.com/winduum/winduum/blob/main/src/base/defaults.css) ```css ::selection { color: var(--color-primary-foreground); background-color: var(--color-primary); } :where([tabindex]) { outline: 0; } :where(button), :where([type="checkbox"]), :where([type="radio"]), :where([role="button"]), :where(summary) { touch-action: manipulation; user-select: none; } :where(button:enabled), :where([type="checkbox"]:enabled), :where([type="radio"]:enabled), :where([role="button"]:not([aria-disabled="true"])), :where(summary) { cursor: var(--cursor-pointer, pointer); } :where(svg:not([width])) { width: 1.25rem; } :where(svg:not([height])) { height: 1.25rem; } :where(hr) { background-color: color-mix(in var(--default-color-space), currentcolor 100%, transparent); block-size: 1px; inline-size: 100%; } :where(code) { padding: calc(var(--spacing) * 1) calc(var(--spacing) * 2); background-color: var(--color-body-secondary); border-radius: var(--radius-sm); color: var(--color-accent); } :where(kbd) { padding: calc(var(--spacing) * 1) calc(var(--spacing) * 2); background: var(--color-body-secondary); border-radius: var(--radius-sm); border: 1px solid var(--color-body-tertiary); } :where(html) { color-scheme: var(--default-color-scheme); font-family: var(--font-primary); font-weight: var(--font-weight-normal); block-size: 100%; line-height: 1.5; text-size-adjust: 100%; @media (prefers-reduced-motion: no-preference) { scroll-behavior: smooth; } } :where(body) { min-block-size: 100%; background-color: var(--color-body); color: var(--color-main); accent-color: var(--color-accent); } [hidden] { display: none !important; } ``` For TailwindCSS `v3` there are few rules such as resetting borders and applying `--tw-content` to all pseudo-elements and zero border to all elements or pseudo-elements. [`tailwindcss/base/defaults.css`](https://github.com/winduum/winduum/blob/main/tailwindcss/base/defaults.css) ## Cursor Default `cursor: pointer` for clickable elements, you can change this globally via CSS property `--default-cursor` if you prefer more application like behavior. ## Svg Set the default size of an SVG as a small square if neither width nor height is specified. ```html ``` ## Hr Just a horizontal rule. ```html
``` ## Code ```html Cool code ``` ## Kbd ```html Ctrl+C/⌘+C ``` ## Html & Body Basic text and color properties --- --- url: /docs/components/details.md --- # Details An accessible accordion or toggle component for `details` and `summary` elements. Uses small external library `slide-element` for smooth toggle animations. It is unstyled by default, so you can apply your own styles. ### Dependencies * [slide-element](https://www.npmjs.com/package/slide-element) ### Usage ::: code-group ```shell npm i slide-element ``` ```html
Show more
Details content
``` ```js import { toggleDetails } from 'winduum/src/components/details' document.querySelectorAll('[data-action="toggleDetails"]').forEach(summary => { summary.addEventListener('click', event => { if (event.currentTarget.tagName !== 'INPUT') event.preventDefault() toggleDetails(summary) }) }) ``` ::: ### Installation Follow instructions for individual framework usage below ## Examples ### Default ```liquid \[js] ``` ### Checkbox ```liquid \[js] ``` ### Accordion ```liquid \[js] ``` ## Javascript API ```typescript interface DefaultOptions { selector?: string summarySelector?: string } ``` ### toggleDetails * **Type:** `(selector: HTMLInputElement | HTMLElement, options?: DefaultOptions) => Promise` * **Kind:** `async` Toggles a details element, should be added on summary or anywhere inside the details element. ### showDetails * **Type:** `(selector: HTMLInputElement | HTMLElement, options?: DefaultOptions) => Promise` * **Kind:** `async` Shows a details element, should be added on `summary` or anywhere inside the `details` element. ### closeDetails * **Type:** `(selector: HTMLInputElement | HTMLElement, options?: DefaultOptions) => Promise` * **Kind:** `async` Closes a details element, should be added on `summary` or anywhere inside the `details` element. --- --- url: /docs/components/dialog.md --- # Dialog Modal component that uses native HTML5 `dialog` functionality. ## Usage ::: code-group ```css @import "winduum/src/components/dialog/index.css" layer(utilities); ``` ```js import { showDialog } from 'winduum/src/components/dialog' document.querySelector('#showDialog').addEventListener('click', () => { showDialog(document.querySelector('dialog')) }) ``` ```vue ``` ::: ### Variants ### Props ### Installation Follow instructions for individual framework usage below ## Example ::: code-group ```html
Example dialog

You can close this dialog with Esc, clicking outside, or by form submit


``` ```vue ``` ::: ## JavaScript API ### `showDialog` * **Type:** `(selector: HTMLDialogElement, options?: DefaultOptions) => Promise` * **Kind:** `async` Shows an existing ``. It takes a `selector` argument, which is a CSS selector that identifies the dialog DOM element to be displayed. It also takes an options argument, which is an object that specifies how the dialog should be displayed. The `closeDialog` event is sent upon closing with the `esc` key or clicking outside the dialog content window. #### Example ```js import { showDialog } from 'winduum/src/libraries/dialog' document.querySelector('#showDialog').addEventListener('click', async () => { await showDialog(document.querySelector('#dialogElement')) }) ``` #### `DefaultOptions` *** ##### remove * **Type:** `boolean` * **Default:** `true` A boolean that indicates whether the dialog should be removed from the DOM when it is closed. *** ##### closable * **Type:** `boolean` * **Default:** `true` A boolean that indicates whenever is dialog closable by clicking outside or with `esc` key. *** ##### modal * **Type:** `boolean` * **Default:** `true` Determines if the dialog is shown as modal on top-layer. *** ##### openAttribute * **Type:** `string` * **Default:** `data-open` A string representing a data attribute that will be added when the dialog is fully visible. *** ##### closedAttribute * **Type:** `string` * **Default:** `data-closed` A string representing a data attribute that will be added once the dialog starts closing. *** ##### contentSelector * **Type:** `string` * **Default:** `.x-dialog-content` A string representing a CSS selector representing the dialog content *** ##### scrollbarWidthProperty * **Type:** `string` * **Default:** `--default-scrollbar-width` A CSS property representing a scrollbar width, when dialog is shown the document scrollbar is hidden, this adds necessary padding. *** ### `closeDialog` * **Type:** `(selector: HTMLDialogElement, options?: DefaultOptions) => Promise` * **Kind:** `async` Closes an existing ``. It takes a `selector` argument, which is a CSS selector that identifies the dialog DOM element. It also takes an `options` argument, which is an object that specifies how the dialog should be closed. When dialog closes it sends native `close` event you can listen to, additionally `x-dialog:close` event is sent when dialog animation starts. #### Example ```js import { closeDialog } from 'winduum/src/components/dialog' document.querySelector('#closeDialog').addEventListener('click', async () => { await closeDialog(document.querySelector('#dialogElement')) }) ``` --- --- url: /docs/utilities/divide-gap.md --- # Divide Gap Provides a new TailwindCSS utility classes `divide-gap-x` and `divide-gap-y` for easier way to do gap between [Divide](https://tailwindcss.com/docs/divide-width) utility classes. You can use all values from [Spacing scale](https://tailwindcss.com/docs/customizing-spacing#default-spacing-scale). ## TailwindCSS v4 Include CSS file with the `@utility` at-rule. ```css @import "winduum/tailwindcss/utilities/divide-gap.css"; ``` ## TailwindCSS v3 Add plugin via the `tailwind.config.js`, see [Config](/docs/base/config#tailwind-css-v3) for more info. ## Example ```html
01
02
03
``` --- --- url: /docs/utilities/dot.md --- # Divide Gap Provides a new utility class `dot` for.. well dots! ## Example ```html
``` --- --- url: /docs/utilities/divider.md --- # Divider Provides a new utility class `divider` so you can easily separate content. ## Examples ### Basic ```html
OR
``` ### Vertical ```html
OR
``` ### Custom ```html
OR
``` --- --- url: /docs/components/drawer.md --- # Drawer Provides a scroll drawer that uses native HTML5 `dialog` and CSS `scroll-snap` property. Can be dismissed with touch gestures on touch devices. ### Usage ::: code-group ```css @import "winduum/src/components/drawer/index.css" layer(utilities); ``` ```liquid \[js] ``` ### Variants ### Props ### Installation Follow instructions for individual framework usage below ## Examples ### Left ```liquid \[js] ``` ### Right ```liquid \[js] ``` ### Bottom ```liquid \[js] ``` ### Top ```liquid \[js] ``` ## Javascript API ### `showDrawer` * **Type:** `(element: HTMLElement | Element, distance: number, direction: 'left' | 'top') => void` * **Kind:** `sync` Scroll the drawer to open state. ### `closeDrawer` * **Type:** `(element: HTMLElement | Element, distance: number, direction: 'left' | 'top') => void` * **Kind:** `sync` Scroll the drawer to closed state. ### `scrollInitDrawer` * **Type:** `(element: HTMLElement | Element, distance?: number, direction?: 'left' | 'top') => void` * **Kind:** `sync` Initializes the scroll position. Call this before `showDrawer` method. ### `scrollDrawer` * **Type:** `(element: HTMLElement | Element, options: ScrollDrawerOptions) => void` * **Kind:** `sync` Sets correct classes and attributes upon scroll. Events `c-drawer:open` and `c-drawer:close` are dispatched upon opening or closing the drawer. #### ScrollDrawerOptions *** ##### snapClass * **Type:** `string` * **Default:** `snap-x snap-mandatory` A classes that are added for snapping purposes once the drawer is open. *** ##### opacityProperty * **Type:** `string` * **Default:** `--tw-bg-opacity` A CSS property for animating the background opacity upon scroll. *** ##### opacityRatio * **Type:** `number` * **Default:** `1` You can either set `1` or `0` depending on the direction the drawer is opened. Right and bottom drawer should be set to `0`. *** ##### scrollOpen * **Type:** `number` * **Default:** `0` Scroll position indicating that the drawer is opened. *** ##### scrollClose * **Type:** `number` * **Default:** `element.scrollWidth - element.clientWidth` Scroll position indicating that the drawer is closed. *** ##### scrollSize * **Type:** `number` * **Default:** `element.scrollWidth - element.clientWidth` Maximum scroll size of the drawer. *** ##### scrollDirection * **Type:** `number` * **Default:** `element.scrollLeft` Current scroll position of the drawer. --- --- url: /docs/components/field.md --- # Field Component used to group a form components. ### Variants ### Installation Follow instructions for individual framework usage below ### Usage ```css @import "winduum/src/components/field/index.css" layer(utilities); ``` ## Examples ### Basic ```html
Info message
``` --- --- url: /docs/components/form.md --- # Form Provides a basic way to validate your form and show feedback to your users with native HTML5 form validation. Use attributes such as [pattern](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/pattern) to add other validation rules. `novalidate` must be present on `form` to handle validation with JavaScript. ::: info Compatible with any reactive framework, but updates will not propagate to the virtual DOM. For advance form of validation use [VeeValidate](https://vee-validate.logaretm.com/v4/), [React Hook Form](https://react-hook-form.com/) or others. ::: ### Installation Follow instructions for individual framework usage below ### Usage ```liquid \[js] ``` ## Examples ### Form ```liquid \[js] ``` ### Field ```liquid \[js] ``` ## Javascript API ### `validateForm` * **Type:** `(event: Event | SubmitEvent, options?: ValidateFormOptions) => void` * **Kind:** `sync` Validates a form with [checkValidity](https://developer.mozilla.org/en-US/docs/Web/API/HTMLSelectElement/checkValidity) and [validateField](/docs/components/form#validatefield) events. #### ValidateFormOptions *** ##### validateSelectors * **Type:** `string` * **Default:** `.x-control, .x-check, .x-switch, .x-rating, .x-color` Selectors which will be validated. *** ##### validateOptions * **Type:** `ValidateFieldOptions` * **Default:** `{}` Additional options for `validateField` *** ##### submitterLoadingAttribute * **Type:** `string` * **Default:** `data-loading` Loading class that will be added to a submitter element, e.g., A button. *** ##### scrollOptions * **Type:** `ScrollIntoViewOptions` * **Default:** `{ behavior: 'smooth', block: 'center' }` Scroll options when scrolling to an invalid element. ### `validateField` * **Type:** `(selector: HTMLElement, options?: ValidateFieldOptions) => void` * **Kind:** `sync` Validates a field. This can be element such as `.x-control`, `x-check` and others that can be validated. It adds validation info message inside `c-field` and validation icon inside `x-control`. It also adds a `valid`, `invalid` or `active` class to the element. #### ValidateFieldOptions *** ##### validate * **Type:** `boolean` * **Default:** `true` Only `active` class is added if the element value is not empty. No other validation is done. *** ##### selector * **Type:** `string` * **Default:** `input:not([type="hidden"]), textarea, select` *** ##### ignoreMatch * **Type:** `RegExp` * **Default:** `/(data-novalidate|readonly)/` Ignores a validation if any of these strings are present in the HTML. *** ##### validitySelector * **Type:** `string` * **Default:** `.validity` Selector for dynamically added content in the DOM such us info message or icon. *** ##### infoParentSelector * **Type:** `string` * **Default:** `.x-field` *** ##### infoSelector * **Type:** `string` * **Default:** `.x-info` *** ##### infoContent * **Type:** `string` * **Default:** `
` *** ##### endParentSelector * **Type:** `string` * **Default:** `.x-control` *** ##### endSelector * **Type:** `string` * **Default:** `.ms-auto` *** ##### endContent * **Type:** `string` * **Default:** `
` *** ##### validAttribute * **Type:** `string` * **Default:** `data-valid` *** ##### validIcon * **Type:** `string | null` * **Default:** `null` *** ##### invalidAttribute * **Type:** `string` * **Default:** `data-invalid` *** ##### invalidIcon * **Type:** `string` * **Default:** `` *** ##### activeAttribute * **Type:** `string` * **Default:** `data-active` --- --- url: /docs/grid.md --- # Grid It's recommended to use the following TailwindCSS approaches to shape your layout * [Grid](https://tailwindcss.com/docs/grid-template-columns) * [Flex](https://tailwindcss.com/docs/flex) * [Gap](https://tailwindcss.com/docs/gap) Winduum also provides additional utilities to make things even easier. * [Container](/docs/utilities/container) * [Divide Gap](/docs/utilities/divide-gap) --- --- url: /docs/components/group.md --- # Group Group common ui components such as [Button](/docs/components/button), [Badge](/docs/components/badge) or [Control](/docs/components/control) together. ### Usage ```css @import "winduum/src/components/group/index.css" layer(utilities); ``` ### Variants ### Tokens ### Installation Follow instructions for individual framework usage below ## Examples ### Button Group ```html \[html]
``` ```vue ``` ```jsx import { Group } from '@/components/group' import { Button } from '@/components/button' export function Example() { return ( <> ) } ``` ::: ### Badge Group ```html
Badge
Badge
Badge
Badge
Badge
Badge
Badge
Badge
Badge
npm
7.1.2
``` ### Control Group ```html
@
``` ### Vertical Group ```html
Link
``` ```html
``` --- --- url: /docs/components/heading.md --- # Heading For common heading styles that you can manage from one component across project. ### Usage ```css @import "winduum/src/components/heading/index.css" layer(utilities); ``` ### Tokens * `sm` * `lg` ### Installation Follow instructions for individual framework usage below ## Examples ### Basic ```html \[html]
Heading
``` ```vue ``` ```jsx import { Heading } from '@/components/heading' export function Example() { return ( Heading ) } ``` ::: ### Small ```html

Heading H3

``` ### Large ```html

Heading H1

``` ### Weight ```html

Heading H1

``` --- --- url: /docs/icons.md --- # Icons It's recommended to use icons as svg, such as [Heroicons](https://heroicons.com/) Winduum uses some of them internally via CSS custom properties. ```css :root { --x-check-icon-mask: url('data:image/svg+xml,'); --x-check-radio-icon-mask: url('data:image/svg+xml, '); } /* Example */ .icon-check { background-color: currentColor; mask: var(--x-check-icon-mask); width: 1rem; height: 1rem; } ``` You can also use your svg icons via `` method. Define a global `
``` ```vue ``` ```jsx import { UiImage } from '@/components/image' export function Example() { return ( ) } ``` ::: ### Rounded ```html
``` ### Avatar ```html
LB
``` ### Skeleton ```html
``` ### Iframe ```html
``` --- --- url: /docs/components/info.md --- # Info Small informative component. ### Usage ```css @import "winduum/src/components/info/index.css" layer(utilities); ``` ### Variants ### Props ### Installation Follow instructions for individual framework usage below ## Examples ### Basic ```html \[html] Info text ``` ```vue ``` ```jsx import { Info } from '@/components/info' export function Example() { return ( Info text ) } ``` ::: --- --- url: /docs.md --- # Install You can use Winduum with or without [TailwindCSS](https://tailwindcss.com/). Check out the [About](/docs/about) page to learn more about Winduum and its philosophy. Winduum `2.x` is using compatible naming for CSS custom properties that work with both current and old versions of TailwindCSS, specifically `v4` and `v3`. ## Get started You can install Winduum via **npm** and use it in your **Node.js** project. Or copy and paste the components from source and make it your own. You can also mix both approaches, everything is possible! See [Trying Winduum Online](#trying-winduum-online) section below to see all possible examples of use. ### npm ```shell npm i winduum ``` The components are written in plain CSS, so sources can be also loaded in browsers without a build step or used in any other build tool such as **PostCSS** or **LightningCSS**. ```css @import "winduum/src/theme/index.css" layer(theme); @import "winduum/src/base/index.css" layer(base); @import "winduum/src/components/index.css" layer(utilities); @import "winduum/src/utilities/index.css" layer(utilities); ``` Or you can include components separately, follow usage steps with each component. ```css @import "winduum/src/theme/index.css" layer(theme); @import "winduum/src/base/index.css" layer(base); @import "winduum/src/components/button/index.css" layer(utilities); @import "winduum/src/utilities/index.css" layer(utilities); ``` Or paste the source code to your project and make it your own! ```css @import "@/styles/theme/index.css" layer(theme); @import "@/styles/base/index.css" layer(base); @import "@/styles/components/button/index.css" layer(utilities); @import "@/styles/utilities/index.css" layer(utilities); ``` With `layer(utilities)` you can use TailwindCSS variant classes, for example `class="x-button lg:square"` to make button square only from `lg` breakpoint. (Not wokring with TailwindCSS v4 currently) ### TailwindCSS It's optional but recommended to leverage the full functionality of the library! #### v4 To use TailwindCSS `v4`, you will have to import TailwindCSS and Winduum imports individually. ```css @import "tailwindcss/theme.css" layer(theme); @import "winduum/tailwindcss/theme/config/index.css" layer(theme); @import "winduum/tailwindcss/theme/default.css" layer(theme); @import "winduum/src/theme/dark.css" layer(theme); @import "winduum/src/base/reset.css" layer(base); @import "winduum/src/base/defaults.css" layer(base); /* single imports for your components and utilities, or you can include them separately in your project (recommended) */ @import "winduum/src/components/index.css" layer(utilities); @import "winduum/src/utilities/container/props/default.css" layer(theme); @import "winduum/src/utilities/ripple/keyframes/default.css"; @import "winduum/src/utilities/skeleton/props/default.css" layer(theme); @import "winduum/src/utilities/spinner/keyframes/ring.css"; @import "winduum/tailwindcss/utilities/index.css"; @import "tailwindcss/utilities" layer(utilities); @import "winduum/tailwindcss/variants/index.css"; @import "winduum/src/base/breakpoints.css"; @import "winduum/src/base/keyframes.css"; @import "winduum/src/base/transitions.css"; ``` TailwindCSS `v4` can be used in any project with Vite and works out of the box. No `tailwind.config.js` needed! All configuration is done in CSS! ```javascript import tailwindcss from '@tailwindcss/vite' import { defineConfig } from 'vite' export default defineConfig({ plugins: [tailwindcss()], }) ``` #### v3 To use TailwindCSS `v3`, you will have to import TailwindCSS and Winduum imports individually. ```css @import "winduum/src/theme/index.css"; @import "winduum/src/base/index.css"; @import "winduum/src/components/index.css" layer(utilities); @import "winduum/src/utilities/index.css" layer(utilities); @import "winduum/tailwindcss/base/defaults.css"; @import "tailwindcss/base.css"; @import "tailwindcss/components.css"; @import "tailwindcss/utilities.css"; @import "tailwindcss/variants.css"; ``` Follow the installation steps in [TailwindCSS](https://v3.tailwindcss.com/docs/installation) docs and include Winduum as a plugin, see [Config](/docs/base/config#tailwind-css-v3) for more info. ## PostCSS or LightingCSS For TailwindCSS `v3` following PostCSS plugins are required. If you are using `v4` the [LightingCSS](https://lightningcss.dev/) is used out of the box. * [`autoprefixer`](https://www.npmjs.com/package/autoprefixer) * [`tailwindcss`](https://www.npmjs.com/package/tailwindcss) * [`postcss-nesting`](https://www.npmjs.com/package/postcss-nesting) * [`postcss-import`](https://www.npmjs.com/package/postcss-import) * [`postcss-custom-media`](https://www.npmjs.com/package/postcss-custom-media) If you are not using TailwindCSS, you can use whatever you want, even no build step! ## Stylelint It's also recommended to use [Stylelint](https://stylelint.io/) with [stylelint-stylistic](https://github.com/stylelint-stylistic/stylelint-stylistic) to help add conventions to your styles. You can check and use basic `.stylelintrc` for Winduum [here](https://github.com/winduum/winduum/blob/main/.stylelintrc). ```shell npm i stylelint stylelint-config-standard @stylistic/stylelint-config --save-dev ``` ## CSS Pre-processors If you want to use pre-processors like `sass` or `less` you can. But if you want to use [TailwindCSS](#tailwindcss) be sure to follow a guide how to use it with [Preprocessors](https://tailwindcss.com/docs/using-with-preprocessors) ## CDN This is meant only for basic usage. Only basic styles are included for TailwindCSS, such as colors and font variants. To leverage the full functionality of the framework, [TailwindCSS](#tailwindcss) and build step is recommended. ```html ``` ## Trying Winduum Online On [StackBlitz](https://stackblitz.com/) or [GitHub](https://github.com/winduum/winduum/tree/main/examples) with basic examples how to use it in [Vite](https://vitejs.dev/) and other frameworks. * vite * vite + vue * vite + react * vite + svelte * vite + solid * vite + qwik * vite + lit - astro - nuxt - next - htmx - vite + sass - vite + less Winduum is **framework-agnostic**, learn more on the [About](/docs/about#framework-agnostic) page. Do you need ready to use components? Here are components ready to copy & paste. For now there are only a few, more might come in the future! Each component in docs includes example usage in `html` and also in `vue` and `jsx`. --- --- url: /docs/base/keyframes.md --- # Keyframes Following keyframes are provided in [`src/base/keyframes.css`](https://github.com/winduum/winduum/blob/main/src/base/keyframes.css). ```css @keyframes spin { to { transform: rotate(360deg); } } @keyframes fade-in { from { opacity: 0%; } } @keyframes fade-out { to { opacity: 0%; } } ``` --- --- url: /docs/components/label.md --- # Label ### Usage ```css @import "winduum/src/components/label/index.css" layer(utilities); ``` ### Variants ### Props ### Installation Follow instructions for individual framework usage below ## Examples ### Basic ```html \[html]
``` ```vue ``` ```jsx import { Label } from '@/components/label' export function Example() { return ( ) } ``` ::: --- --- url: /docs/layers.md --- # Layers All component styles are written with low specificity in mind. This ensures that any utility classes have higher specificity. You can also leverage [CSS Layers](https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Cascade_layers) to have even better control of your specificity. This can be also combined with [TailwindCSS layers](https://tailwindcss.com/docs/adding-custom-styles#using-css-and-layer). ## TailwindCSS v4 Future version of TailwindCSS uses layers by default, so no configration is needed. ## TailwindCSS v3 If you want to write CSS [per-component](https://tailwindcss.com/docs/adding-custom-styles#layers-and-per-component-css), be aware that here you cannot use TailwindCSS layers. Well you could, but it would have some unfortunate side effects of utility classes leaking into components. You can use layers globally like this. ```css @layer winduum-base, winduum-components, winduum-utilities, winduum-variants; @import "winduum/src/base/index.css" layer(base); @import "winduum/src/components/index.css" layer(utilities); @import "winduum/src/components/index.css" layer(utilities); @import "winduum/src/utilities/index.css" layer(utilities); @layer winduum-base { @tailwind base; } @layer winduum-components { @tailwind components; } @layer winduum-utilities { @tailwind utilities; } @layer winduum-variants { @tailwind variants; } ``` --- --- url: /docs/components/link.md --- # Link ### Usage ```css @import "winduum/src/components/link/index.css" layer(utilities); ``` ### Variants ### Props ### Installation Follow instructions for individual framework usage below ## Examples ### Basic ```html \[html] Link Default Link Accent ``` ```vue ``` ```jsx import { Link } from '@/components/link' export function Example() { return ( <> Link Default Link Primary ) } ``` ::: ### Underline ```html Link Default Link Primary ``` --- --- url: /docs/components/notice.md --- # Notice ### Usage ```css @import "winduum/src/components/notice/index.css" layer(utilities); ``` ### Variants ### Props ### Installation Follow instructions for individual framework usage below ## Examples ### Success ```html \[html] ``` ```vue ``` ```jsx import { Notice } from '@/components/notice' export function Example() { return ( Success notice ) } ``` ::: ### Error ```html ``` ### Warning ```html ``` ### Info ```html ``` ### Text ```html ``` ### Background ```html ``` --- --- url: /docs/components/pagination.md --- # Pagination ### Usage ```css @import "winduum/src/components/pagination/index.css" layer(utilities); ``` ### Variants ### Installation Follow instructions for individual framework usage below ## Example ```html ``` --- --- url: /docs/components/popover.md --- # Popover Popover can be used for dropdowns and other popovers when an element is clicked and focused. You have following types of trigger as an option: * trigger on focus with CSS `trigger-focus` class * trigger on hover with CSS `trigger-hover` class * trigger on click with JS and the `[popover]` attribute ### Dependencies * [floating-ui](https://floating-ui.com/) - for `[popover]` trigger ## Usage ::: code-group ```css @import "winduum/src/components/popover/index.css" layer(utilities); ``` ```html \[html]
Popover
``` ```vue ``` ::: ### Variants ### Tokens Applicable to `x-popover-content` * `bottom bottom-start` * `bottom bottom-end` * `top top-start` * `top top-end` * `right right-start` * `right right-end` * `left left-start` * `left left-end` * `bottom inline-center` * `top inline-center` * `right block-center` * `left block-center` ### Installation Follow instructions for individual framework usage below ## Examples ### focus-trigger ```html
Popover
``` ### hover-trigger ```html
Popover
``` ### \[popover] This is using advantages of [Popover API](https://developer.mozilla.org/en-US/docs/Web/API/Popover_API) with [floating-ui](https://floating-ui.com/). It's also backwards compatible as it's leveraging only the `showPopover` and `hidePopover` for the [top-layer](https://developer.mozilla.org/en-US/docs/Glossary/Top_layer) support. Popover is placed dynamically upon available space, and auto updates itself when needed. ```html
``` ## JavaScript API ### `showPopover` * **Type:** `(element: HTMLElement | Element, options?: ShowPopoverOptions) => Promise` * **Kind:** `async` #### Example ```js import { showPopover, hidePopover } from '/src/components/popover' const popoverActionElement = document?.querySelector('[popovertargetaction="show"]') popoverActionElement?.addEventListener('click', async (e) => { e.preventDefault() const currentTarget = e.currentTarget await showPopover(currentTarget, { placement: 'right-end', }) }) // close on esc window.addEventListener('keydown', ({ key }) => { if (key === 'Escape') { hidePopover(popoverActionElement) } }) // outside dismiss window.addEventListener('click', ({ target }) => { if (!window.popover?.contains(target) && !popoverActionElement?.isEqualNode(target) && popoverActionElement?.ariaExpanded === 'true') { hidePopover(popoverActionElement) } }) ``` #### `ShowPopoverOptions` *** ##### anchorSelector * **Type:** `string` * **Default:** `undefined` By default, the anchor selector is the trigger button, you can change this to other selector. *** ##### openAttribute * **Type:** `string` * **Default:** `data-open` A string representing an attribute that will be added when popover is visible. *** ##### compute * **Type:** `boolean` * **Default:** `true` Determines if the popover should be anchored and computed with `@floating-ui/dom` *** ##### placement * **Type:** `Placement` * **Default:** `undefined` Determines [placement](https://floating-ui.com/docs/computePosition#placement) of the popover with `@floating-ui/dom`, also adds a corresponding class to the popover target. *** ##### middleware * **Type:** `Array` * **Default:** `[offset(12 ?? options?.offset), flip(options?.flip), shift({ padding: 8, ...options?.shift })]` Customize [middleware](https://floating-ui.com/docs/computePosition#middleware) for `@floating-ui/dom` *** ##### offset * **Type:** `OffsetOptions` * **Default:** `12` Customize [offset](https://floating-ui.com/docs/offset#options) options for `@floating-ui/dom` *** ##### flip * **Type:** `FlipOptions` * **Default:** `undefined` Customize [flip](https://floating-ui.com/docs/flip#options) options for `@floating-ui/dom` *** ##### shift * **Type:** `ShiftOptions` * **Default:** `undefined` Customize [shift](https://floating-ui.com/docs/shift#options) options for `@floating-ui/dom` *** ### `hidePopover` * **Type:** `(element: HTMLElement | Element) => Promise` * **Kind:** `async` #### Example ```js import { hidePopover } from '/src/components/popover' const popoverActionElement = document?.querySelector('[popovertargetaction="hide"]') popoverActionElement?.addEventListener('click', async (e) => { e.preventDefault() const currentTarget = e.currentTarget await hidePopover(currentTarget) }) ``` ### `togglePopover` * **Type:** `(element: HTMLElement | Element, options?: ShowPopoverOptions) => Promise` * **Kind:** `async` #### Example ```js import { togglePopover, hidePopover } from '/src/components/popover' const popoverActionElement = document?.querySelector('[popovertargetaction="toggle"]') popoverActionElement?.addEventListener('click', async (e) => { e.preventDefault() const currentTarget = e.currentTarget await togglePopover(currentTarget) }) // close on esc window.addEventListener('keydown', ({ key }) => { if (key === 'Escape') { hidePopover(popoverActionElement) } }) // outside dismiss window.addEventListener('click', ({ target }) => { if (!window.popover?.contains(target) && !popoverActionElement?.isEqualNode(target) && popoverActionElement?.ariaExpanded === 'true') { hidePopover(popoverActionElement) } }) ``` --- --- url: /docs/components/progress.md --- # Progress Displays progress with native HTML5 tags `progress` or `meter` ### Usage ```css @import "winduum/src/components/progress/index.css" layer(utilities); ``` ### Variants ### Props ### Tokens * `sm` * `lg` ### Installation Follow instructions for individual framework usage below ## Examples ### Colors ```html \[html] ``` ```vue ``` ```jsx import { UiProgress } from '@/components/progress' export function Example() { return ( <> ) } ``` ::: ### Small ```html ``` ### Large ```html ``` ### Indeterminate ```html ``` ### Meter ```html 25 out of 45 ``` --- --- url: /docs/components/range.md --- # Range Accessible range slider that allows easy selection of a value by sliding a handle. ### Usage ::: code-group ```css @import "winduum/src/components/range/index.css" layer(utilities); ``` ```js import { setValue } from 'winduum/src/components/range' const rangeSlider = document.querySelector('#rangeSlider') setValue(rangeSlider) rangeSlider.addEventListener('input', ({ currentTarget }) => setValue(currentTarget)) ``` ::: ### Variants * `default` * `multi` ### Props ### Tokens * `vertical` ### Installation Follow instructions for individual framework usage below ## Examples ### Default ```liquid \[js] ``` ```vue ``` ```jsx import { Range } from '@/components/range' export function Example() { return ( ) } ``` ::: ### Multi ```liquid \[js] ``` ### Vertical ```liquid \[js] ``` ## Javascript API ### setTrackProperty * **Type:** `(options: TrackOptions, track: 'start' | 'end') => void` * **Kind:** `sync` #### TrackOptions *** ##### element * **Type:** `HTMLElement | Element` * **Default:** `undefined` *** ##### value * **Type:** `string` * **Default:** `undefined` *** ##### min * **Type:** `number` * **Default:** `undefined` *** ##### max * **Type:** `number` * **Default:** `undefined` *** ### setValue * **Type:** `(element: HTMLInputElement, options: SetValueOptions) => void` * **Kind:** `sync` #### DefaultOptions *** ##### selector * **Type:** `string` * **Default:** `.x-range` *** ##### track * **Type:** `string` * **Default:** `'start' | 'end'` *** ### setOutputValue * **Type:** `(element: HTMLInputElement, options: SetOutputOptions) => void` * **Kind:** `sync` #### SetOutputOptions *** ##### lang * **Type:** `string` * **Default:** `document.documentElement.lang` *** ##### formatOptions * **Type:** `Intl.NumberFormatOptions` * **Default:** `{ style: 'decimal', minimumFractionDigits: 0, maximumFractionDigits: 0 }` --- --- url: /docs/components/rating.md --- # Rating ### Usage ```css @import "winduum/src/components/rating/index.css" layer(utilities); ``` ### Variants ### Props ### Installation Follow instructions for individual framework usage below ## Examples ### Basic ```html \[html]
``` ```vue ``` ```jsx import { Rating } from '@/components/rating' export function Example() { return ( ) } ``` ::: --- --- url: /docs/base/reset.md --- # Reset New modern CSS reset, that means [Preflight](https://tailwindcss.com/docs/preflight#border-styles-are-reset-globally) from **TailwindCSS** is disabled by default. You can always enable it again via `tailwind.config.js` if you prefer it more. Everything except [Defaults](https://github.com/winduum/winduum/blob/main/src/base/defaults.css) is unstyled, so you are free to style your components or use pre-built components. [`src/base/reset.css`](https://github.com/winduum/winduum/blob/main/src/base/reset.css) ```css /* Reset all */ :where(a), :where(address), :where(button), :where(blockquote), :where(body), :where(caption), :where(cite), :where(code), :where(dd), :where(details), :where(dialog), :where(dl), :where(dt), :where(em), :where(fieldset), :where(figcaption), :where(figure), :where(h1, h2, h3, h4, h5, h6), :where(hgroup), :where(hr), :where(input), :where(kbd), :where(label), :where(legend), :where(li), :where(mark), :where(menu), :where(ol), :where(optgroup), :where(option), :where(output), :where(p), :where(select), :where(summary), :where(table), :where(td), :where(textarea), :where(th), :where(thead), :where(time), :where(tr), :where(ul), :where(progress), :where(meter), :where([popover]) { all: unset; display: revert; } /* Revert table vertical-align */ :where(tr, th, td), :where(thead, tbody, tfoot) { vertical-align: revert; background-color: inherit; } /* Reset block */ :where(img), :where(svg), :where(video), :where(canvas), :where(audio), :where(iframe), :where(embed), :where(object), :where(search), :where(hr), :where(summary), :where(pre > code) { display: block; } /* Improve consistency of default fonts in all browsers. */ :where(code), :where(kbd), :where(samp), :where(pre) { font-family: ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace; font-size: 1em; } /* Preferred box-sizing value */ :where(*), :where(*)::before, :where(*)::after { box-sizing: border-box; -webkit-tap-highlight-color: rgb(255 255 255 / 0%); } /** Prevent 'sub' and 'sup' elements from affecting the line height in all browsers. */ :where(sub, sup) { vertical-align: baseline; font-size: 100%; } :where(sub) { font-variant-position: sub; } :where(sup) { font-variant-position: super; } /* Add the correct text decoration in Chrome, Edge, and Safari. */ :where(abbr[title]) { text-decoration: underline dotted; } /* Reapply the pointer cursor for anchor tags */ :where(a, button) { cursor: revert; } /* Remove list styles (bullets/numbers) */ :where(ol:not([type]), ul, menu) { list-style-type: ""; } /* For images to not be able to exceed their container */ :where(img, iframe) { max-inline-size: 100%; max-block-size: 100%; } /* removes spacing between cells in tables */ :where(table) { border-collapse: collapse; } /* Safari - solving issue when using user-select:none on the text input doesn't working */ :where(input, textarea) { user-select: auto; cursor: revert; background-color: revert; } /* revert the 'white-space' property for textarea elements on Safari */ :where(textarea) { white-space: revert; } /* reset default text opacity of input placeholder */ ::placeholder { color: unset; } /* revert for bug in Chromium browsers - fix for the content editable attribute will work properly. - webkit-user-select: auto; added for Safari in case of using user-select:none on wrapper element */ :where([contenteditable]:not([contenteditable="false"])) { overflow-wrap: break-word; -webkit-line-break: after-white-space; user-select: auto; } /* apply back the draggable feature - exist only in Chromium and Safari */ :where([draggable="true"]) { -webkit-user-drag: element; } /* Fix input styles */ :where(input) { &::-webkit-datetime-edit-fields-wrapper, &::-webkit-datetime-edit-text, &::-webkit-datetime-edit, &::-webkit-datetime-edit-hour-field, &::-webkit-datetime-edit-minute-field { padding: 0; } &::-webkit-calendar-picker-indicator, &::-webkit-search-cancel-button { align-self: center; background-position: 50% 50%; } } /* Remove details summary webkit styles */ ::-webkit-details-marker { display: none; } ``` --- --- url: /docs/utilities/ripple.md --- # Ripple A material ripple effect that is visible on clicking, you can use it with or without JS by adding `animation-ripple` class. Use with [Button](/docs/components/button) or any other component. ## Usage ::: code-group ```css @import "winduum/utilities/ripple.css" layer(utilities); ``` ```js import { showRipple } from 'winduum/src/utilities/ripple' document.querySelector('#showRipple').addEventListener('click', (e) => { showRipple({ element: e.currentTarget, x: e.offsetX, y: e.offsetY }) }) ``` ```vue ``` ::: ## Example ::: code-group ```html ``` ```js import { showRipple } from 'winduum/src/utilities/ripple' document.querySelector('#showRipple').addEventListener('click', (e) => { showRipple({ element: e.currentTarget, x: e.offsetX, y: e.offsetY }) }) ``` ::: ## Javascript API ### showRipple * **Type:** `(event: MouseEvent | ShowRippleEvent, rippleElement?: HTMLElement) => ` * **Kind:** `sync` ```typescript interface ShowRippleEvent { currentTarget?: EventTarget | HTMLElement; offsetX: number; offsetY: number; } ``` Shows an animated ripple effect on an element --- --- url: /docs/utilities/skeleton.md --- # Skeleton Introduces a utility class `skeleton` for loading state of a page or a component. ```css .skeleton { background: linear-gradient( to right, var(--skeleton-gradient-from), var(--skeleton-gradient-to), var(--skeleton-gradient-to), var(--skeleton-gradient-from) ); opacity: var(--skeleton-opacity); transition: var(--transition-opacity); animation: move-indeterminate 1.5s linear infinite; background-size: 400% 100%; } ``` ## Example ```html
``` --- --- url: /docs/utilities/swap.md --- # Swap Provides a new utility class `swap` to toggle between elements. ## Examples ### Basic ```html ``` ### Aria ```liquid \[js] ``` --- --- url: /docs/utilities/spinner.md --- # Swap Provides a new utility class `spinner` for circular animated spinners. ## Examples ### Basic ```html
``` ### Custom ```html
``` --- --- url: /docs/components/switch.md --- # Switch ### Usage ```css @import "winduum/src/components/switch/index.css" layer(utilities); ``` ### Variants ### Props ### Installation Follow instructions for individual framework usage below ## Examples ### Basic ```html \[html]
Switch
``` ```vue ``` ```jsx import { Switch } from '@/components/switch' export function Example() { return ( Switch ) } ``` ::: ### Small ```html
``` ### Large ```html
``` ### Disabled ```html
Switch
``` --- --- url: /docs/components/table.md --- # Table Display your data in non-interactive, interactive or responsive tables. ### Usage ```css @import "winduum/src/components/table/index.css" layer(utilities); ``` ### Variants ### Props ### Installation Follow instructions for individual framework usage below ## Examples ### Default ```html
Full name Email Employment
Agata Henderson a.henderson@example.com Interpreter
Tony Johnston t.johnston@example.com Singer
Maya Walker m.walker@example.com Lawer
``` ### Interactive ```html
Name Vacation Late arrival Employment Meeting Homeoffice Doctor Pause Worked time Total time
John Smith
Programmer
20 days 12 Full time 0:00 h 0:00 h 0:00 h 0:18 h 0:00 h 0:00 h
John Smith
Programmer
20 days 12 Full time 0:00 h 0:00 h 0:00 h 0:18 h 0:00 h 0:00 h
John Smith
Programmer
20 days 12 Full time 0:00 h 0:00 h 0:00 h 0:18 h 0:00 h 0:00 h
``` ### Advanced ```html
Product summary
Clothes Accessories
Trousers Skirts Dresses Bracelets Rings
Belgium Antwerp 56 22 43 72 23
Gent 46 18 50 61 15
Brussels 51 27 38 69 28
The Netherlands Amsterdam 89 34 69 85 38
Utrecht 80 12 43 36 19
Sum NaN
``` --- --- url: /docs/components/tabs.md --- # Tabs ### Usage ```css @import "winduum/src/components/tabs/index.css" layer(utilities); ``` ### Variants ### Installation Follow instructions for individual framework usage below ## Examples ### Default ```liquid \[js] ``` ### Custom ```liquid \[js] ``` ## Javascript API ### `toggleTab` * **Type:** `(element: HTMLElement | Element, options?: ToggleTabOptions) => void` * **Kind:** `sync` Toggles tab and tab panel aria attributes. #### ToggleTabOptions *** ##### tabElements * **Type:** `NodeListOf` * **Default:** `undefined` Elements representing tabs. ##### tabPanelElements * **Type:** `NodeListOf` * **Default:** `undefined` Elements representing tab panels. --- --- url: /docs/components/text.md --- # Text Typographic defaults for common wysiwyg content. It's an alternative to [prose](https://tailwindcss.com/docs/typography-plugin). ### Usage ```css @import "winduum/src/components/text/index.css" layer(utilities); ``` ### Variants ### Props ### Installation Follow instructions for individual framework usage below ## Examples ### Text ```html \[html]

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec eget efficitur metus. In bibendum nisi et dui sagittis efficitur. Proin porttitor diam at quam finibus, quis porttitor turpis ullamcorper. Quisque iaculis imperdiet nunc in hendrerit. Nulla facilisi. Sed at sodales ex. Vivamus ornare auctor ligula et lobortis. Nunc metus augue, tristique vitae sagittis ac, interdum eu nisl. Curabitur aliquet, lectus ut interdum commodo, ipsum elit gravida libero, in laoreet lectus nisl a erat. Sed consequat justo pulvinar turpis pharetra mattis. Phasellus non pretium libero.

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

``` ```vue ``` ```jsx import { UiText } from '@/components/text' export function Example() { return (

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec eget efficitur metus. In bibendum nisi et dui sagittis efficitur. Proin porttitor diam at quam finibus, quis porttitor turpis ullamcorper. Quisque iaculis imperdiet nunc in hendrerit. Nulla facilisi. Sed at sodales ex. Vivamus ornare auctor ligula et lobortis. Nunc metus augue, tristique vitae sagittis ac, interdum eu nisl. Curabitur aliquet, lectus ut interdum commodo, ipsum elit gravida libero, in laoreet lectus nisl a erat. Sed consequat justo pulvinar turpis pharetra mattis. Phasellus non pretium libero.

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

) } ``` ::: ### Headings ```html

h1 heading

h2 heading

h3 heading

h4 heading

h5 heading
h6 heading
``` ### Lists ```html
  • Lorem ipsum dolor sit amet, consectetur. Donec eget efficitur metus In bibendum nisi et dui
  • Donec eget efficitur metus

  • Lorem ipsum dolor sit amet, consectetur. Donec eget efficitur metus In bibendum nisi et dui
  • Donec eget efficitur metus

  • Lorem ipsum dolor sit amet, consectetur. Donec eget efficitur metus In bibendum nisi et dui
  • Donec eget efficitur metus

  1. Lorem ipsum dolor sit amet, consectetur. Donec eget efficitur metus In bibendum nisi et dui
  2. Donec eget efficitur metus
  1. Coffee
  2. Tea
  3. Milk
  1. Coffee
  2. Tea
  3. Milk
  1. Coffee
  2. Tea
  3. Milk
  1. Coffee
  2. Tea
  3. Milk
  1. Coffee
  2. Tea
  3. Milk
``` ### Blockquote ```html
Ut venenatis, nisl scelerisque sollicitudin fermentum, quam libero hendrerit ipsum, ut blandit est tellus sit amet turpis.
``` ### Table ```html
# First Last Handle
1 Mark Otto @mdo
2 Jacob Thornton @fat
3 Larry the Bird @twitter
``` ### Figure ```html
Figure 1: Some beautiful placeholders
``` ### Iframe ```html
``` --- --- url: /docs/base/theme.md --- # Theme Theming in Winduum is really easy. All it takes is a few CSS properties. There are two themes by default (light and dark) and to create a new one, you can just extend the default theme. ## Default Each `color-mix` function also contains `--default-color-space` property, which you can change from `sRGB` to mix colors in different color spaces. You can use colors in any format you want. ### TailwindCSS v4 Instead of `:root, :host` the `v4` `@theme` at-rule is used. [`tailwindcss/theme/default.css`](https://github.com/winduum/winduum/blob/main/tailwindcss/theme/default.css) ### TailwindCSS v3 [`src/theme/default.css`](https://github.com/winduum/winduum/blob/main/src/theme/default.css) ```css :root, :host { --default-color-space: srgb; --default-color-scheme: light; --color-accent: var(--color-primary); --color-accent-foreground: var(--color-primary-foreground); --color-primary: #3b82f6; /* color.blue.500 */ --color-primary-foreground: var(--color-light); --color-main: #171717; /* color.neutral.900 */ --color-main-foreground: var(--color-body); --color-main-primary: var(--color-main); --color-main-secondary: color-mix(in var(--default-color-space), var(--color-main) 75%, var(--color-main-foreground)); --color-main-tertiary: color-mix(in var(--default-color-space), var(--color-main) 50%, var(--color-main-foreground)); --color-body: #fff; /* color.white */ --color-body-foreground: var(--color-main); --color-body-primary: var(--color-body); --color-body-secondary: color-mix(in var(--default-color-space), var(--color-body) 95%, var(--color-body-foreground)); --color-body-tertiary: color-mix(in var(--default-color-space), var(--color-body) 90%, var(--color-body-foreground)); --color-light: #fff; /* color.white */ --color-light-foreground: var(--color-dark); --color-dark: #171717; /* color.neutral.900 */ --color-dark-foreground: var(--color-light); --color-success: #16a34a; /* color.green.600 */ --color-error: #dc2626; /* color.red.600 */ --color-warning: #eab308; /* color.yellow.500 */ --color-info: #0ea5e9; /* color.sky.500 */ } ``` ## Default P3 [`src/theme/default-p3.css`](https://github.com/winduum/winduum/blob/main/src/theme/default-p3.css) Better high range colors for P3 capable displays. ```css :root, :host { @media (color-gamut: p3) { --color-primary: color(display-p3 0.23 0.51 0.96); --color-main: color(display-p3 0.09 0.09 0.09); --color-body: color(display-p3 1 1 1); --color-light: color(display-p3 1 1 1); --color-dark: color(display-p3 0.09 0.09 0.09); --color-success: color(display-p3 0.09 0.64 0.29); --color-error: color(display-p3 0.86 0.15 0.15); --color-warning: color(display-p3 0.92 0.7 0.03); --color-info: color(display-p3 0.05 0.65 0.91); } } ``` ## Dark [`src/theme/dark.css`](https://github.com/winduum/winduum/blob/main/src/theme/dark.css) ```css :root.dark, :host.dark { --default-color-scheme: dark; --color-main: var(--color-light); --color-body: var(--color-dark); } ``` ## Compatibility Support for `color-mix` is almost `90%` global usage. But if you want better compatibility you can still use `rgb` which can be enabled it in the [Config](/docs/base/config.html#settings-rgb) (only for TailwindCSS v3). In that case, you have to use rgb variants for theming in your own components. * [`src/theme/default-rgb.css`](https://github.com/winduum/winduum/blob/main/src/theme/default-rgb.css) * [`src/theme/dark-rgb.css`](https://github.com/winduum/winduum/blob/main/src/theme/dark-rgb.css) --- --- url: /docs/components/title.md --- # Title For common title styles that you can manage from one component across project. ### Usage ```css @import "winduum/src/components/title/index.css" layer(utilities); ``` ### Variants ### Props ### Tokens * `sm` * `lg` ### Installation Follow instructions for individual framework usage below ## Examples ### Basic ```html \[html]
Title
``` ```vue ``` ```jsx import { Title } from '@/components/title' export function Example() { return ( Title ) } ``` ::: ### Small ```html

Title H3

``` ### Large ```html

Title H1

``` ### Weight ```html

Title H1

``` ### Uppercase ```html
Title
``` ### Color ```html
Title
``` --- --- url: /docs/components/toast.md --- # Toast Let it bake and fly from your [Toaster](/docs/components/toaster)! ## Usage ::: code-group ```css @import "winduum/src/components/toast/index.css" layer(utilities); ``` ```js import { showToast, closeToast } from 'winduum/src/components/toaster' document.querySelector('#insertToast').addEventListener('click', async () => { const toaster = document.querySelector('.x-toaster') toaster.insertAdjacentHTML('beforeend', `
  • Hello toast
    Amazing toast
  • `) await showToast(toaster.children[toaster.children.length - 1]) const closeToastButton = document.querySelectorAll('[data-action="closeToast"]')[document.querySelectorAll('[data-action="closeToast"]').length - 1] closeToastButton.addEventListener('click', ({ currentTarget }) => { closeToast(currentTarget.closest('.c-toast')) }) }) ``` ```html
      ``` ::: ### Variants ### Installation Follow instructions for individual framework usage below ## Example ::: code-group ```html
        ``` ::: ## JavaScript API ### `showToast` * **Type:** `(selector: HTMLElement, options?: ShowToastOptions) => Promise` * **Kind:** `async` Applies an enter animation to existing toast. #### Example ```js import { showToast } from 'winduum/src/components/toaster' document.querySelector('#showToast').addEventListener('click', async () => { await showToast(document.querySelector('#toastElement')) }) ``` #### ShowToastOptions *** ##### openAttribute * **Type:** `string` * **Default:** `data-open` *** ##### autoHide * **Type:** `number` * **Default:** `null` *** ##### heightProperty * **Type:** `string` * **Default:** `--x-toast-height` *** ##### close * **Type:** `CloseToastOptions` * **Default:** `{}` *** ### `closeToast` * **Type:** `(selector: HTMLElement, options?: CloseToastOptions) => Promise` * **Kind:** `async` Applies an exit animation to existing toast and removes it from DOM. #### Example ```js import { showToast } from 'winduum/src/components/toaster' document.querySelector('#closeToast').addEventListener('click', async () => { await closeToast(document.querySelector('#toastElement')) }) ``` #### CloseToastOptions *** ##### closedAttribute * **Type:** `data-closed` * **Default:** `out` *** ##### heightProperty * **Type:** `string` * **Default:** `--x-toast-height` *** --- --- url: /docs/components/toaster.md --- # Toaster Bake your [Toast](/docs/components/toast) and let it fly! You should insert in into your `` ## Usage ```css @import "winduum/src/components/toaster/index.css" layer(utilities); ``` ### Variants ### Installation Follow instructions for individual framework usage below ## Example ```html
          ``` ### `closeToaster` * **Type:** `(selector: HTMLElement, options?: CloseToastOptions) => Promise` * **Kind:** `async` All toasts are closed at once. #### Example ```js import { showToast } from 'winduum/src/components/toaster' document.querySelector('#closeToaster').addEventListener('click', async () => { await closeToaster(document.querySelector('.c-toaster')) }) ``` --- --- url: /docs/tokens.md --- # Tokens Every component has class tokens which you can use for component customization. These tokens can be used with TailwindCSS variants. For example `x-heading max-md:sm` changes the size on the `md` breakpoint. This was possible automatically with TailwindCSS `v3`, since `v4` this is not working anymore (see [#16000](https://github.com/tailwindlabs/tailwindcss/issues/16000)). To replicate the same functionality, you have to use the new `@utility` at-rule manually. None of the components use this by default. **Example of a custom component with default import:** (variants will not work) ```css @import "winduum/src/components/heading/index.css" layer(utilities); /* this file includes following imports @import "winduum/src/components/heading/props/default.css"; @import "winduum/src/components/heading/default.css"; @import "winduum/src/components/heading/sm.css"; @import "winduum/src/components/heading/lg.css"; */ ``` **Example of a custom component with custom import:** (you will have to include all tokens manually and variants will work) ```css @import "winduum/src/components/heading/props/default.css" layer(theme); @import "winduum/src/components/heading/default.css" layer(utilities); @layer theme { :root, :host { --x-heading-font-weight: var(--font-bold); /* any custom properties */ } } @layer utilities { .x-heading { /* any custom styles */ } } @utility sm { .x-heading:is(&) { --x-heading-font-size: var(--text-lg); } } @utility lg { .x-heading:is(&) { --x-heading-font-size: var(--text-3xl); } } ``` --- --- url: /docs/components/tooltip.md --- # Tooltip Tooltip can be used for a little info hint on hover or focus. ## Usage ::: code-group ```css @import "winduum/src/components/tooltip/index.css" layer(utilities); ``` ```html \[html]
          ``` ```vue ``` ::: ### Variants ### Tokens * `top` * `bottom` * `left` * `right` ### Installation Follow instructions for individual framework usage below ## Examples ### Basic ```html
          ``` --- --- url: /docs/base/transitions.md --- # Transitions This activates the [View Transitions API](https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API) with cross-document animations. CSS properties can be changed via [Config](https://github.com/winduum/winduum/blob/main/src/theme/config.css). [`src/base/transitions.css`](https://github.com/winduum/winduum/blob/main/src/base/transitions.css) ```css @view-transition { navigation: auto; } ::view-transition-group(main) { animation-duration: var(--view-transition-main-duration); } ::view-transition-new(main) { animation-delay: var(--view-transition-main-duration); } ``` Add `view-transition-main` class to any element you want to animate page navigation. [`src/utilities/view-transition.css`](https://github.com/winduum/winduum/blob/main/src/utilities/view-transition.css) ```css .view-transition-main { view-transition-name: main; } ``` --- --- url: /docs/utilities/underline.md --- # Underline Extends [`underline`](https://tailwindcss.com/docs/text-decoration) utility class for easy underline animations. ```css .underline { text-underline-offset: var(--default-underline-offset, 0.125em); } .underline-transparent { &:where(:any-link, button:enabled, [role="button"]) { transition: all var(--default-transition-duration) var(--ease-in-out); &:not(:hover, :focus-visible) { text-underline-offset: var(--default-underline-transparent-offset, -0.25em); text-decoration-color: transparent; } } } ``` ## Example ```html Link Default Link Primary ```