Haupia ("how-PEE-ah")

A component library of tasty little blocks, made with a few simple ingredients.

No build step. No JavaScript. No CSS processing. Just HTML and CSS, with simple APIs.

by Jeff Yaus

Overview

Haupia is a lightweight (just 28K minified!) component library for webpages, designed to be simple to use, to install, and to modify. It is made from just pure CSS, meaning no build steps, no JavaScript dependencies, no CSS processing to configure, no image directory to set up. While maybe not as feature-rich as some component libraries, Haupia is ideal when you want a minimum of fuss. Just drop the stylesheet onto your page, and you're off!

Usage

To install Haupia, just copy the stylesheet into your site, and link to it from your page. That's it! Go (coco)nuts!

Haupia only styles the CSS classes that are part of its API; it won't affect anything else on your page, so it is easily used alongside your existing CSS, or even alongside another front-end framework.

This simpler components just use the relevant HTML tag, plus a class of haupia- and the name of the element. For instance, a Haupia checkbox is a regular <input type="checkbox"> plus the class haupia-checkbox. More complex components might need additional wrapper or sibling elements. (Code examples are given below.)

Themes

The default theme is built around a bunch of CSS variables, found at the top of the stylesheet. These are easily modified to fit your site's own palette, typography, and look-and-feel. For instance, you can change the background color of the basic buttons by adjusting the value of --haupia-button-background-color to your preferred color.

License

Haupia is free to use, under the MIT license.

Buttons

The basic button can be used on a variety of HTML tags.

<a> tag <span> tag
<button class="haupia-button">Button text</button> <a href="somewhere" class="haupia-button">Button text</a> <span class="haupia-button" role="button" tabindex="0"> Button text </span> <input type="submit" class="haupia-button" value="Button text" />

Button sizes and variants

Buttons can be made larger or smaller, and can take different variants (skins).

<button class="haupia-button haupia-button-large"> Large button </button> <button class="haupia-button haupia-button-secondary"> Secondary button </button> <button class="haupia-button haupia-button-small haupia-button-danger"> Small danger button </button>

Form inputs

Checkbox

Switch

Like a checkbox, a toggle switch is also an on/off indicator, so it is treated as a checkbox.

<input type="checkbox" class="haupia-checkbox" /> <input type="checkbox" class="haupia-switch" />

Radio buttons

<input type="radio" class="haupia-radio" name="exampleRadio" value="exampleValue" />

Radio buttonbar

Radio buttons can also be presented as a bar of buttons.

<fieldset class="haupia-radio-buttonbar" role="toolbar"> <input type="radio" id="exampleRadio1" name="exampleRadio" value="exampleValue" /> <label class="haupia-radio-buttonbar-button" for="exampleRadio1"> Button Text </label> </fieldset>

Dropdown

<select class="haupia-select"> <option>Option 1</option> <option>Option 2</option> </select>

Text input

Textarea

<input type="text" class="haupia-input-text" /> <textarea class="haupia-textarea"></textarea>

Input group

An input group combines a text input with a button and/or some static elements into a single visual display.

$ .00
@
@haupia.yum
<div class="haupia-input-group"> <span class="haupia-input-group-static">$</span> <input type="text" class="haupia-input-text" /> <span class="haupia-input-group-static">.00</span> </div> <div class="haupia-input-group" role="group"> <input type="text" class="haupia-input-text" /> <input type="submit" value="Search" class="haupia-button" /> </div>

Disabled form elements

When disabled, form elements get a washed-out look.

Presentation

Alert

<div class="haupia-alert" role="alert"> I am a default alert. </div> <div class="haupia-alert haupia-alert-error" role="alert"> I am an error alert. </div>

Dismissable alerts

Alerts can be dismissable; a click on the "x" icon will hide the alert.

I am an info alert that is dismissible.
<input type="checkbox" id="myDismissibleAlert" class="haupia-close-button-checkbox" /> <label for="myDismissibleAlert" class="haupia-close-button"> <span class="haupia-visually-hidden"> Dismiss this alert </span> </label>

Breadcrumbs

<ul class="haupia-breadcrumbs" role="navigation"> <li><a href="#">Link 1</a></li> <li><a href="#">Link 2</a></li> <li>Not a Link 3</li> </ul>

Loading spinner

<span class="haupia-spinner" aria-live="polite" role="status"><span>

Badge

A paragraph of text with a badge in it.

default secondary danger light

You can also use a badge to show a number:

<span class="haupia-badge">default badge</span> <span class="haupia-badge haupia-badge-secondary">secondary badge</span>

Progress

This is a styled version of the progress tag, a visual meter. (To show progress along a series of steps, see Progress List below.)

<progress class="haupia-progress" value="70" max="100"></progress>

Progress List

The progress list shows the current progress along a series of steps.

  • Completed step
  • Current step
  • Future step
<ul class="haupia-progress-list"> <li class="haupia-progress-list-complete">Completed step</li> <li class="haupia-progress-list-current" aria-current="step">Current step</li> <li>Future step</li> </ul>

Interactive controls

Tooltip

Hover over me to see a tooltip.

<div class="haupia-tooltip"> <p>I am the regular content.</p> <aside class="haupia-tooltip-content" role="tooltip"> I am the tooltip content. </aside> </div>

Accordion

For content that collapses and expands.

Click me to expand/collapse
I am the accordion content.
I am the accordion content.
I am the accordion content.
I am the accordion content.

An accordion with multiple panels:

Click me to expand/collapse
I am the accordion content.
I am the accordion content.
I am the accordion content.
I am the accordion content.
Click me to expand/collapse
I am the accordion content.
I am the accordion content.
I am the accordion content.
I am the accordion content.
Click me to expand/collapse
I am the accordion content.
I am the accordion content.
I am the accordion content.
I am the accordion content.
<div class="haupia-accordion"> <details class="haupia-details"> <summary class="haupia-summary"> Click me to expand/collapse </summary> <div class="haupia-details-content"> I am the accordion content. </div> </details> </div>

with header text that changes

Accordions can be set to have different header text when expanded vs. collapsed.

See More See Less
I am the accordion content.
I am the accordion content.
I am the accordion content.
I am the accordion content.
<div class="haupia-accordion"> <details class="haupia-details"> <summary class="haupia-summary"> <span class="haupia-summary-content-closed"> See More </span> <span class="haupia-summary-content-open"> See Less </span> </summary> <div class="haupia-details-content"> I am the accordion content. </div> </details> </div>

with unstyled content

An "unstyled" accordion removes the bounding border and the inset on the text.

Here is some text content above the unstyled accordion.

Click me to expand/collapse
I am the accordion content.
I am the accordion content.
I am the accordion content.
I am the accordion content.
Click me to expand/collapse
I am the accordion content.
I am the accordion content.
I am the accordion content.
I am the accordion content.
Click me to expand/collapse
I am the accordion content.
I am the accordion content.
I am the accordion content.
I am the accordion content.
// as above, but add class // "haupia-accordion-unstyled" // to the accordion.

Tabs

Tabs use radio buttons to control which tab is shown. Set the default tab's radio button to checked.

Tab 1 content
Tab 2 content
Tab 3 content
<div class="haupia-tabs" role="tablist"> <input type="radio" name="exampleTabs" value="1" id="exampleTab1" checked="checked" role="tab" aria-controls="tabpanel1"> <label for="exampleTab1" id="tablabel1">Tab 1</label> <div class="haupia-tabs-content" id="tabpanel1" role="tabpanel" aria-labelledby="tablabel1"> Tab 1 content, shown by default </div> <input type="radio" name="exampleTabs" value="2" id="exampleTab2" role="tab" aria-controls="tabpanel2"> <label for="exampleTab2" id="tablabel2">Tab 2</label> <div class="haupia-tabs-content" id="tabpanel2" role="tabpanel" aria-labelledby="tablabel2"> Tab 2 content </div> </div>

using "simple" variant

The "simple" variant gives the tabs a simpler display.

Tab 1 content using "simple" variant
Tab 2 content using "simple" variant
Tab 3 content using "simple" variant
// as above, but add class "haupia-tabs-simple" // to the outermost container

Typography

Heading

You can use any of the Haupia heading classes on any of the H1-H6 tags, depending on the desired visual appearance of a given heading.

H1 with class "haupia-h1"

H2 with class "haupia-h2"

H3 with class "haupia-h3"

H4 with class "haupia-h4"

H5 with class "haupia-h5"
H6 with class "haupia-h6"

H1 using class "haupia-h3" instead of "haupia-h1"

<h1 class="haupia-h1">Heading Level 1</h1>

Inside a block with class "haupia-type":

For convenience, you can also wrap a section with the class haupia-type. Any headings inside that section will then automatically get Haupia's heading styling.

H1 with no class on it

H2 with no class on it

H3 with no class on it

H4 with no class on it

H5 with no class on it
H6 with no class on it

H1 using class "haupia-h3"

<div class="haupia-type"> <h1>Heading Level 1</h1> </div>

Blockquote

I am a blockquote, used for quotes that are longer pieces of text.
<blockquote class="haupia-blockquote"> Blockquote text goes here. </blockquote>

Lists

  • Unordered List 1
  • Unordered List 2
  • Unordered List 3
  1. Ordered List 1
  2. Ordered List 2
  3. Ordered List 3

using "unstyled" variant

The unstyled variant removes any list-specific styling — useful when your items are semantically a list, but shouldn't appear as one.

  • Unordered List 1
  • Unordered List 2
  • Unordered List 3
<ul class="haupia-ul"> <li>Unordered List 1</li> <li>Unordered List 2</li> </ul> <ol class="haupia-ol"> <li>Ordered List 1</li> <li>Ordered List 2</li> </ol> <ul class="haupia-ul haupia-ul-unstyled"> <li>Unordered List 1</li> <li>Unordered List 2</li> </ul>

Text alignment

Text aligned left.

Text aligned center.

Text aligned right.

H5 with "haupia-h5" and aligned right.
<p class="haupia-text-left">Text aligned left.</p> <p class="haupia-text-center">Text aligned center.</p> <p class="haupia-text-right">Text aligned right.</p>

Code block


<p>Code line 1</p>
<p>Code line 2</p>
<p>Code line 3 is really, really long and will likely be wider than the bounding box, because holy cats, is this a long line.</p>
<p>Code line 4</p>
<p>Code line 5</p>
<p>Code line 6</p>
                
<pre class="haupia-code-block"> <code> Code example goes here </code> </pre>

Browser Support

What makes Haupia's code so simple is its extensive use of CSS custom properties (aka CSS variables) and CSS filters, so it works in any browser that supports these features (which is basically all modern browsers).

The close buttons inside dismissible Alerts use the :has feature of CSS, which as of May 2023 is not supported by Firefox and some older versions of Safari. If those browsers are on your supported browser list, you should avoid using dismissible Alerts, since clicking on the close button will not close the component.

Accessibility

Haupia's listed APIs include as much accessibility support as HTML and CSS alone can provide. But Haupia is a CSS-only library, and full accessibility support for your page may sometimes require JavaScript. Please follow the WCAG guidelines.

Haupia provides a visible focus-visible indicator for its components. If you want this style to apply to all focusable elements on your page, so that your page is visually consistent, add this CSS:

            
*:focus {outline: var(--haupia-focus-outline);}

*:focus-visible p {outline: var(--haupia-focus-visible-outline);}