Skip to content

Migrate from Pico CSS

Planning to migrate from Pico CSS to WovenUI? This guide shows what moves from classless HTML to WovenUI core and the kit.

This page is for teams that like Pico CSS because plain semantic HTML already looks finished, and want the same calm look with a token system and more components. Pico styles tags directly. WovenUI splits the job in two: the core base layer styles a small set of elements without classes, and @wovenui/components adds wu- classes for everything else. Install the kit from the install page. For the framework-level comparison, read WovenUI vs Pico CSS.

Core’s base layer gives you a classless start: body takes the page background and text color, <button> (and submit, button and reset inputs) and form fields (<input>, <textarea>, <select>) are styled from tokens with a focus ring. An invalid field, marked with aria-invalid="true", gets the danger border.

Other elements, such as <article>, <table>, <dialog>, <details> and <nav>, are not styled by core. The kit styles them when you add a class. That keeps your own markup free of surprises: a tag outside a kit component looks like a plain tag. The kit keeps your semantic elements (<nav>, <article>, <dialog>, <details>, <table>) and adds a class to them, so the markup stays semantic.

Pico WovenUI Notes
<button> <button> Styled by core base; add wu-btn for variants and sizes
<button class="secondary"> <button class="wu-btn"> The plain kit button is the neutral one
<button class="outline"> <button class="wu-btn brand subtle"> A tinted outline, the closest match
<div role="group"> around buttons <div class="wu-btn-group"> Pressed state from aria-pressed="true"
<input>, <select>, <textarea> Same tags Styled by core base; add wu-input, wu-select, wu-textarea for sizes
aria-invalid="true" on a field aria-invalid="true" Same attribute, handled by core base
<label> around a field <div class="wu-field"> with <label class="wu-field-label"> Hint in <p class="wu-field-message">; link it with aria-describedby
<article> <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 open> with <article> <dialog class="wu-modal"> Opened with commandfor and command="show-modal", no script
<details> <div class="wu-accordion"> of <details class="wu-accordion-item"> Keeps the native element; no script
<nav> with <ul> groups <header class="wu-topbar"> with <nav class="wu-topbar-nav"> Brand in <a class="wu-topbar-brand">; wu-topbar-nav also works on the <ul>
<nav aria-label="breadcrumb"> <nav class="wu-breadcrumb"> Wraps <ol class="wu-breadcrumb-list">
<table> <table class="wu-table"> Also striped, hover, bordered, sm
<progress> <progress class="wu-progress"> On a native <progress>; roles such as danger color it
.container container Centered, with responsive max widths
.grid grid cols-1 cols-3@md gap-4 Pico’s columns collapse below 768px, the md breakpoint in core
data-theme="light" or "dark" data-theme="light" or "dark" Same attribute on any element; "inverse" is also available
dir="rtl" dir="rtl" Same attribute; see Right to left
--pico-border-radius --wu-radius-md Tokens use the --wu- prefix; override on :root or any selector

Layout around the components uses core utilities, so a card grid is grid, cols-1, cols-3@md and gap-4, not a kit class. Read more in Grid and Theming. The breakpoint names and sizes (md, lg) are core defaults, set by the $breakpoints setting; see the configuration page.

Pico styles <dialog>, but opening one still needs your own script. The kit’s modal and drawer open from a button with commandfor and command="show-modal", so you write no script. The dropdown and popover work the same way with the popover attribute, and the accordion is <details>, as in Pico.

  • Classes are opt-in. Pico styles every tag by default. Core styles only the base set above, and kit components appear where you add wu- classes.
  • Variants are bare words. Kit modifiers sit next to the root and are valid only together with it: wu-btn brand sm. Colors use the core role names, so there is no primary or contrast.
  • Native elements. Modals are <dialog> opened with commandfor and command, menus and popovers use the popover attribute, and accordions are <details>. Pico leaves opening a dialog to your own script; the kit needs none for these.
  • State lives in attributes. Pressed, selected and current states come from aria-pressed, aria-selected and aria-current.
  • More components. The kit adds components Pico does not document, such as tabs, drawers, toasts, a data table, an autocomplete and a sidebar. Browse the component pages in the sidebar.
  • No icon set. The kit ships no icons. Markers such as the select arrow and the close cross are drawn in CSS.
  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.