Valence.css
Classless CSS that still loves your custom elements — Pico's elegance, remixed for the modern web.
Valence.css is a lightly modified fork of the excellent Pico CSS. Pico styles are tightly bound to native tag names (article, button, …), which custom elements cannot reuse. Valence.css keeps Pico's look and adds:
- Tag aliases —
@custom-selectorsynonyms so[role="…"]/.tag-*(and custom element tags) share the same semantic styles - Opt-outs —
.unstyled/.unstyled-all(and.unanimated*) for document flexibility where framework styles would fight you - Drop-in themes —
basic(Pico-faithful) ships today; further themes share the same tokens so they can be swapped without touching markup. Light/dark is a scheme ([data-scheme]) - Molecules — cards, dropdowns, modals (
dialog::backdrop/[role="presentation"]/.tag-backdrop), nav, progress, and native[popover]styles on top of Pico's element styles - Tokens —
--pico-*renamed to--v-*for a clear Valence.css namespace
Features
- Semantic tag aliases Style
article,dialog,button, … — the same rules apply to the[role="…"]/.tag-*forms - Custom-element friendly
class="tag-article"on any host inherits Valence.css styles without rewriting selectors - Drop-in themes
basic(Pico-flavor) ships; further themes share the same tokens. Scheme via[data-scheme="light|dark"] - Opt-outs
.unstyled/.unstyled-all(and motion:.unanimated*) - Molecules Cards, dropdowns, modals (
dialog::backdrop/[role="presentation"]/.tag-backdrop), nav, progress, popovers, tooltips
Installation
This package is available in the
<link rel="stylesheet" href="https://unpkg.com/@excom/valence@0.1.3/dist/basic.css">npm install @excom/valence@import "@excom/valence/basic.css";Peer dependencies (0)
Packages a consumer must install alongside this one. Workspace deps are bundled.
| Package | Version |
|---|---|
|
Usage
Import a theme entry (CSS). Prefer aliases when styling custom elements.
@import "@excom/valence/basic.css";@import "@excom/valence/basic.css";<article>Native card</article>
<event-handler class="tag-article">Aliased card</event-handler>
<button class="outline secondary">Outline</button><article>Native card</article>
<event-handler class="tag-article">Aliased card</event-handler>
<button class="outline secondary">Outline</button>Documentation
Getting started
Color schemes — automatic light / dark,data-schemeAliases — tag, role and.tag-*forms of every alias; custom elementsOpt-outs —.unstyled,.unanimated,.abstract
Customization
CSS variables — the--v-*tokensThemes & layers — entries,@layerstrategy, mixins for element authors
Layout
Container ·Landmarks & section ·Grid ·Overflow auto
Content
Typography ·Link ·Button ·Table ·Code ·Embedded content
Forms
Forms ·Input ·Textarea ·Select ·Checkboxes, radios & switches ·Range
Components
Accordion ·Card ·Dropdown ·Group ·Loading ·Modal ·Nav ·Popover ·Progress ·Tooltip
API Reference
Attributes
Role —option is configurable, state
is managed by the element (read-only), or hybrid which is both.
Provision
Thisprovision property lives on the DOM node.
Read / watch it with Quark’s prop("provision"), or listen
for the neutron-provision event from app JS.
Events
Type
command event (HTML Command API): from a
<button command commandfor>, an <event-handler
command-name>, or a CommandEvent.
Recognized Elements
Child or descendant elements are recognized by and relevant to its functionality.Styles
@custom-selector synonyms so custom elements can share
semantic styles. Element aliases match the host tag / .tag-* class; state
aliases match attributes (nested under the element alias).
valence
Attributes (0)
Role —option is configurable, state
is managed by the element (read-only), or hybrid which is both.
Provision (0)
Thisprovision property lives on the DOM node.
Read / watch it with Quark’s prop("provision"), or listen
for the neutron-provision event from app JS.
Events (0)
e.preventDefault() is not
synchronously called on the event.
Type
command event (HTML Command API): from a
<button command commandfor>, an <event-handler
command-name>, or a CommandEvent.
Recognized Elements (0)
Child or descendant elements are recognized by valence and relevant to its functionality.Styles (243)
.close.close or :--button / :--link with rel="prev" Renders the theme close icon (empty content)..container.container-fluid.contrast.dropdown<details> / :--details..grid.nested.outline.secondary / .contrast..overflow-auto.secondary.show-scrollbar.sticky.striped.unanimated.unanimated-all.unstyled.unstyled-allall: revert-layer.
Valence.css ships this as .unstyled and .unstyled-all for the entire tree.
--v-accordion-active-summary-colorvar(--v-primary-hover)--v-accordion-border-colorvar(--v-muted-border-color)--v-accordion-close-summary-colorvar(--v-color)--v-accordion-open-summary-colorvar(--v-muted-color)--v-background-color#fff--v-block-spacing-horizontalvar(--v-spacing)--v-block-spacing-verticalvar(--v-spacing)--v-blockquote-border-colorvar(--v-muted-border-color)--v-blockquote-footer-colorvar(--v-muted-color)--v-border-radius0.25rem--v-border-width0.0625rem--v-box-shadow0.0145rem 0.029rem 0.174rem rgba(129, 145, 181, 0.01698), 0.0335rem 0.067rem 0.402rem rgba(129, 145, 181, 0.024), 0.0625rem 0.125rem 0.75rem rgba(129, 145, 181, 0.03), 0.1125rem 0.225rem 1.35rem rgba(129, 145, 181, 0.036), 0.2085rem 0.417rem 2.502rem rgba(129, 145, 181, 0.04302), 0.5rem 1rem 6rem rgba(129, 145, 181, 0.06), 0 0 0 0.0625rem rgba(129, 145, 181, 0.015)--v-button-box-shadow0 0 0 rgba(0, 0, 0, 0)--v-button-hover-box-shadow0 0 0 rgba(0, 0, 0, 0)--v-card-background-colorvar(--v-background-color)--v-card-border-colorvar(--v-muted-border-color)--v-card-box-shadowvar(--v-box-shadow)--v-card-sectioning-background-colorrgb(251, 251.5, 252.25)--v-code-background-colorrgb(243, 244.5, 246.75)--v-code-color#646b79--v-code-kbd-background-colorvar(--v-color)--v-code-kbd-colorvar(--v-background-color)--v-color#373c44--v-contrast#181c25--v-contrast-background#181c25--v-contrast-bordervar(--v-contrast-background)--v-contrast-focusrgba(93, 107, 137, 0.25)--v-contrast-hover#000--v-contrast-hover-background#000--v-contrast-hover-bordervar(--v-contrast-hover-background)--v-contrast-hover-underlinevar(--v-secondary-hover)--v-contrast-inverse#fff--v-contrast-underlinergba(24, 28, 37, 0.5)--v-del-colorrgb(136, 56.5, 53)--v-dropdown-background-color#fff--v-dropdown-border-color#eff1f4--v-dropdown-box-shadowvar(--v-box-shadow)--v-dropdown-colorvar(--v-color)--v-dropdown-hover-background-color#eff1f4--v-font-familyvar(--v-font-family-sans-serif)--v-font-family-emoji"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"--v-font-family-monospaceui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace, var(--v-font-family-emoji)--v-font-family-sans-serifsystem-ui, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, Helvetica, Arial, "Helvetica Neue", sans-serif, var(--v-font-family-emoji)--v-font-size100%--v-font-weight400--v-form-element-active-background-color#fff--v-form-element-active-border-colorvar(--v-primary-border)--v-form-element-background-colorrgb(251, 251.5, 252.25)--v-form-element-border-color#cfd5e2--v-form-element-color#23262c--v-form-element-disabled-opacity0.5--v-form-element-focus-colorvar(--v-primary-border)--v-form-element-invalid-active-border-colorrgb(200.25, 79.25, 72.25)--v-form-element-invalid-border-colorrgb(183.5, 105.5, 106.5)--v-form-element-invalid-focus-colorvar( --v-form-element-invalid-active-border-color )--v-form-element-placeholder-colorvar(--v-muted-color)--v-form-element-selected-background-color#dfe3eb--v-form-element-spacing-horizontal1rem--v-form-element-spacing-vertical0.75rem--v-form-element-valid-active-border-colorrgb(39, 152.75, 118.75)--v-form-element-valid-border-colorrgb(76, 154.5, 137.5)--v-form-element-valid-focus-colorvar( --v-form-element-valid-active-border-color )--v-grid-column-gapvar(--v-spacing)--v-grid-row-gapvar(--v-spacing)--v-group-box-shadow0 0 0 rgba(0, 0, 0, 0)--v-group-box-shadow-focus-with-button0 0 0 var(--v-outline-width) var(--v-primary-focus)--v-group-box-shadow-focus-with-input0 0 0 0.0625rem var(--v-form-element-border-color)--v-h1-color#2d3138--v-h2-color#373c44--v-h3-color#424751--v-h4-color#4d535e--v-h5-color#5c6370--v-h6-color#646b79--v-icon-checkboxurl("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E")--v-icon-chevronurl("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(136, 145, 164)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E")--v-icon-closeurl("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(136, 145, 164)' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='18' y1='6' x2='6' y2='18'%3E%3C/line%3E%3Cline x1='6' y1='6' x2='18' y2='18'%3E%3C/line%3E%3C/svg%3E")--v-icon-dateurl("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(136, 145, 164)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='16' y1='2' x2='16' y2='6'%3E%3C/line%3E%3Cline x1='8' y1='2' x2='8' y2='6'%3E%3C/line%3E%3Cline x1='3' y1='10' x2='21' y2='10'%3E%3C/line%3E%3C/svg%3E")--v-icon-invalidurl("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(200.25, 79.25, 72.25)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='8' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='16' x2='12.01' y2='16'%3E%3C/line%3E%3C/svg%3E")--v-icon-loadingurl("data:image/svg+xml,%3Csvg fill='none' height='24' width='24' viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg' %3E%3Cstyle%3E g %7B animation: rotate 2s linear infinite--v-icon-minusurl("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='5' y1='12' x2='19' y2='12'%3E%3C/line%3E%3C/svg%3E")--v-icon-searchurl("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(136, 145, 164)' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'%3E%3C/circle%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'%3E%3C/line%3E%3C/svg%3E")--v-icon-timeurl("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(136, 145, 164)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cpolyline points='12 6 12 12 16 14'%3E%3C/polyline%3E%3C/svg%3E")--v-icon-validurl("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(76, 154.5, 137.5)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E")--v-ins-colorrgb(28.5, 105.5, 84)--v-line-height1.5--v-loading-spinner-opacity0.5--v-mark-background-colorrgb(252.5, 230.5, 191.5)--v-mark-color#0f1114--v-modal-overlay-backdrop-filterblur(0.375rem)--v-modal-overlay-background-colorrgba(232, 234, 237, 0.75)--v-multiply-color-0rgba(0, 0, 0, 0.02)--v-multiply-color-1rgba(0, 0, 0, 0.04)--v-muted-border-colorrgb(231, 234, 239.5)--v-muted-color#646b79--v-nav-breadcrumb-divider">"--v-nav-element-spacing-horizontal0.5rem--v-nav-element-spacing-vertical1rem--v-nav-link-spacing-horizontal0.5rem--v-nav-link-spacing-vertical0.5rem--v-outline-width0.125rem--v-popover-background-color#fff--v-popover-border-color#eff1f4--v-popover-box-shadowvar(--v-box-shadow)--v-popover-colorvar(--v-color)--v-popover-max-width20rem--v-primary#0172ad--v-primary-background#0172ad--v-primary-bordervar(--v-primary-background)--v-primary-focusrgba(2, 154, 232, 0.5)--v-primary-hover#015887--v-primary-hover-background#02659a--v-primary-hover-bordervar(--v-primary-hover-background)--v-primary-hover-underlinevar(--v-primary-hover)--v-primary-inverse#fff--v-primary-underlinergba(1, 114, 173, 0.5)--v-progress-background-color#dfe3eb--v-progress-colorvar(--v-primary-background)--v-range-active-border-color#bfc7d9--v-range-border-color#dfe3eb--v-range-thumb-active-colorvar(--v-primary-background)--v-range-thumb-border-colorvar(--v-background-color)--v-range-thumb-colorvar(--v-secondary-background)--v-secondary#5d6b89--v-secondary-background#525f7a--v-secondary-bordervar(--v-secondary-background)--v-secondary-focusrgba(93, 107, 137, 0.25)--v-secondary-hover#48536b--v-secondary-hover-background#48536b--v-secondary-hover-bordervar(--v-secondary-hover-background)--v-secondary-hover-underlinevar(--v-secondary-hover)--v-secondary-inverse#fff--v-secondary-underlinergba(93, 107, 137, 0.5)--v-spacing1rem--v-switch-background-color#bfc7d9--v-switch-checked-background-colorvar(--v-primary-background)--v-switch-color#fff--v-switch-thumb-box-shadow0 0 0 rgba(0, 0, 0, 0)--v-table-border-colorvar(--v-muted-border-color)--v-table-row-stripped-background-colorrgba(111, 120, 135, 0.0375)--v-table-sticky-top0px--v-text-selection-colorrgba(2, 154, 232, 0.25)--v-text-underline-offset0.1rem--v-tooltip-background-colorvar(--v-contrast-background)--v-tooltip-colorvar(--v-contrast-inverse)--v-transitionvar(--v-transition-duration-standard) var(--v-transition-ease-out)--v-transition-duration-fast0.15s--v-transition-duration-slow0.4s--v-transition-duration-standard0.25s--v-transition-ease-incubic-bezier(0.4, 0, 1, 1)--v-transition-ease-in-outcubic-bezier(0.4, 0, 0.2, 1)--v-transition-ease-outcubic-bezier(0, 0, 0.2, 1)--v-typography-spacing-vertical1rem@custom-selector synonyms so custom elements can share
semantic styles. Element aliases match the host tag / .tag-* class; state
aliases match attributes (nested under the element alias).
:--abbrabbr, .tag-abbr:--addressaddress, .tag-address:--articlearticle, [role="article"], .tag-article:--asideaside, [role="complementary"], .tag-aside:--bb, .tag-b:--blockquoteblockquote, [role="blockquote"], .tag-blockquote:--buttonbutton, [role="button"], [type="button"], .tag-button:--button--disabled[disabled], [aria-disabled="true"]:--codecode, [role="code"], .tag-code:--deldel, [role="deletion"], .tag-del:--detailsdetails, .tag-details:--details--open[open], [aria-expanded="true"]:--dialogdialog, [role="dialog"], .tag-dialog:--dialog--open:is(dialog)[open], [aria-expanded="true"]:--dialog-backdrop-aliases[role="presentation"], .tag-backdrop:--dialog-close.close, :is(:--link, :--button)[rel="prev"]:--dldl, .tag-dl:--figcaptionfigcaption, [role="caption"]:is(figure *, [role="figure"] *), .tag-figcaption:--figurefigure, [role="figure"], .tag-figure:--footerfooter, [role="footer"], .tag-footer:--formform, [role="form"], .tag-form:--group[role="group"], .tag-group:--h1h1, [role="heading"][aria-level="1"], .tag-h1:--h2h2, [role="heading"][aria-level="2"], .tag-h2:--h3h3, [role="heading"][aria-level="3"], .tag-h3:--h4h4, [role="heading"][aria-level="4"], .tag-h4:--h5h5, [role="heading"][aria-level="5"], .tag-h5:--h6h6, [role="heading"][aria-level="6"], .tag-h6:--headerheader, [role="header"], .tag-header:--headingh1, h2, h3, h4, h5, h6, [role="heading"], .tag-heading:--hgrouphgroup, .tag-hgroup:--hrhr, [role="separator"], .tag-hr:--imgimg, [role="img"], .tag-img:--insins, [role="insertion"], .tag-ins:--kbdkbd, .tag-kbd:--labellabel, [role="label"], .tag-label:--lili, [role="listitem"], .tag-li:--linka, [role="link"], .tag-link:--listul, ol, [role="list"], .tag-list:--mainmain, [role="main"], .tag-main:--markmark, [role="mark"], .tag-mark:--navnav, [role="navigation"], .tag-nav:--note[role="note"], .tag-note:--olol, .tag-ol:--pp, [role="paragraph"], .tag-p:--popover[popover], .tag-popover:--popover--open:popover-open, [aria-expanded="true"]:--prepre, .tag-pre:--progressprogress, [role="progressbar"], .tag-progress:--progress--indeterminate:is(progress):indeterminate, :is([role="progressbar"], .tag-progress):not(:--progress--value):--progress--value[value], [aria-valuenow]:--progress-aliases[role="progressbar"], .tag-progress:--sampsamp, .tag-samp:--search[role="search"], .tag-search:--sectionsection, [role="section"], .tag-section:--smallsmall, .tag-small:--strongstrong, .tag-strong:--subsub, .tag-sub:--summarysummary, .tag-summary:--supsup, .tag-sup:--tabletable, [role="table"], .tag-table:--tbodytbody, [role="rowgroup"]:has(:--tbody-th, :--td), .tag-tbody:--tbody-thth:not([scope="col"]), [role="rowheader"], [scope="row"], .tag-th-row:--tdtd, [role="cell"], [role="gridcell"], .tag-td:--tfoottfoot, .tag-tfoot:--thth, [role="columnheader"], [role="rowheader"], [scope="col"], [scope="row"], .tag-th:--th--sort[aria-sort]:--th--sort-asc[aria-sort="ascending"]:--th--sort-desc[aria-sort="descending"]:--theadthead, [role="rowgroup"]:has(:--thead-th), .tag-thead:--thead-thth:not([scope="row"]), [role="columnheader"], [scope="col"], .tag-th-col:--trtr, [role="row"], .tag-tr:--tree[role="tree"], .tag-tree:--ulul, .tag-ulRelease notes (3)
0.1.3
- Fix dropdown menus being clipped inside
details.dropdown - Fix the group focus ring showing while no button is focused
- Fix the
aria-busyQuark sample on the Loading page
0.1.2
- Fix an issue where the parent of an
.absolutedialog was forced to 600 by 600 px with a red background
0.1.1
- Ship only dist (and declared extras) in the npm tarball; drop build logs, tests and sources
Release notes
e.preventDefault() is not
synchronously called on the event.
all: revert-layer.
Valence.css ships this as .unstyled and .unstyled-all for the entire tree.