Skip to content
Home Theme Gallery

CSS

The question a host arrives with is not “what does this class do” but “do I need the component at all”. A class is markup the server renders; an element is JavaScript that must boot. Where both are possible, the class is usually right, and the element is right for the specific thing only it can do.

CaseClass, no JavaScriptElement, with behaviourReach for
Table.hui-table on the <table>hui-tableThe class, unless you need row selection, a tri-state header, server-sorted heads or a sticky header that survives a swap
Select.hui-native-select on a native <select>hui-selectThe native select for a plain choice; the element when you want the styled listbox and options the host renders
Radio.hui-radio itemshui-radio-groupBoth together: the group is the element, the items are light DOM, and the class is what styles them
Accordion.hui-accordion__trigger / __panelhui-accordionBoth together: the element wires the behaviour, the classes style the light-DOM children it cannot reach
Label.hui-label on a <label>hui-fieldhui-field when you want the label, description and error wired to the control; the class for a label on its own
Text inputA native <input> the host styleshui-inputThe element, unless you need a type it degrades to text, or native semantics that must not cross a shadow boundary
Everything else in the sheet.hui-card, .hui-badge, .hui-alert, …-The class; no element exists or is planned
  • A class costs nothing at runtime. The server renders it, HTMX swaps it, Alpine binds to it, and it works with JavaScript disabled. Its limit is that it lives in the document, so it cannot hold interaction state or cross a shadow boundary.
  • An element costs a module load and an upgrade. In exchange it can own focus, keyboard, ARIA state and a form value, and it can use the top layer. It also creates a shadow boundary the host’s plain CSS cannot cross - which is why its styling is exposed as tokens and ::part() instead.

Components is one page per thing the class sheet ships as a component in its own right - a card, a badge, a breadcrumb. Each page has the markup it expects, because a class with the wrong markup under it is the most common way these go wrong.

Utilities is what is left once the components are accounted for: the prose rules and the page surface. They are not components, they carry no markup contract, and they are kept apart so the component list is not diluted by them.

Classes that exist only to dress markup inside a custom element - .hui-sidebar-item, .hui-accordion__trigger, .hui-table__sort, .hui-tree__marker - are not here. They are documented on that element’s own page under Components, because they are part of its API rather than something you would reach for on their own.

The elements themselves each have their own page under Components.