alder-ui v0.6.0

alder-ui v0.6.0

A light-DOM, token-based design system with shadcn/ui's look (new-york-v4, neutral): plain CSS in @layer al, plus small scripts that progressively enhance the interactive elements. This page links the built al.css and al.js and shows every element's demo as it renders. The per-element pages, which also show the no-JavaScript fallbacks, are in demo/. Source and docs: github.com/tapegram/alder-ui.

Colour tokens

The colours of the selected theme (Zinc, shadcn's neutral theme, by default). Switch themes above, or re-theme by pasting a shadcn or tweakcn export after al.css.

--background
--foreground
--card
--card-foreground
--popover
--popover-foreground
--primary
--primary-foreground
--secondary
--secondary-foreground
--muted
--muted-foreground
--accent
--accent-foreground
--destructive
--border
--input
--ring
--chart-1
--chart-2
--chart-3
--chart-4
--chart-5
--sidebar
--sidebar-foreground
--sidebar-primary
--sidebar-primary-foreground
--sidebar-accent
--sidebar-accent-foreground
--sidebar-border
--sidebar-ring
--destructive-foreground

al-button

One look, three forms. Put a native <button> inside: it works with no JavaScript (Alder renders the button inside for you). An <a> inside makes a link that looks like a button. The element alone is presentational: it looks like a button but is not one until a framework gives it a role, focus and Enter/Space handling.

Variants

Sizes

Icons

Disabled

Links

All posts Cancel Learn more

The element alone (presentational)

Primary Secondary Outline Ghost Delete Link Disabled

In a form and a column

A button keeps its natural width in a grid form or a column stack. Add full for a full-width button.

Bare Cancel
Bare

al-input

The markup Alder renders for <al-input field="title" label="Title" />: a real <label> around the input, then the help text (when given) and the ul.errors list. help is a <small class="help">; invalid colours the border.

Default

    With help

    The markup Alder renders: a <small class="help"> after the label, named by the control's aria-describedby so a screen reader reads it.

    We never share it.

      The attribute alone also draws the text (but it is not announced):

        Invalid

        • must not be empty

        Disabled

          al-textarea

          The markup Alder renders for <al-textarea field="body" label="Body" />.

          Default

            With help

            The markup Alder renders: a <small class="help"> after the label, named by the control's aria-describedby so a screen reader reads it.

            Markdown is not supported.

              The attribute alone also draws the text (but it is not announced):

                Invalid

                • must not be empty
                • must be at most 5000 characters

                Disabled

                  al-select

                  The markup Alder renders for <al-select field="kind" label="Kind" />. The native select keeps its arrow and keyboard behaviour.

                  Default

                    With help

                    The markup Alder renders: a <small class="help"> after the label, named by the control's aria-describedby so a screen reader reads it.

                    High wakes someone up.

                      The attribute alone also draws the text (but it is not announced):

                        Invalid

                        • must be one of Bug, Feature

                        Disabled

                          al-checkbox

                          The markup Alder renders for <al-checkbox field="done" label="Done" /> on a Bool field. The box is drawn before the text.

                          Default

                            Checked

                              With help

                              The markup Alder renders: a <small class="help"> after the label, named by the control's aria-describedby so a screen reader reads it.

                              One email a month.

                                The attribute alone also draws the text (but it is not announced):

                                  Invalid

                                  • must be checked

                                  Disabled

                                    al-table

                                    Styles the <table> inside it; scrolls sideways when the table is wider than the page.

                                    Default

                                    TitleStatusComments
                                    Hello, worldPublished3
                                    Drafts are fineDraft0
                                    On tokensPublished12
                                    Old newsArchived1

                                    Striped

                                    TitleStatusComments
                                    Hello, worldPublished3
                                    Drafts are fineDraft0
                                    On tokensPublished12
                                    Old newsArchived1

                                    Dense

                                    TitleStatusComments
                                    Hello, worldPublished3
                                    Drafts are fineDraft0
                                    On tokensPublished12
                                    Old newsArchived1

                                    Striped and dense

                                    TitleStatusComments
                                    Hello, worldPublished3
                                    Drafts are fineDraft0
                                    On tokensPublished12
                                    Old newsArchived1

                                    al-card

                                    A bordered surface. Children are placed by slot, whatever their order in the source: header, description and action (the title area), the body, footer, then actions.

                                    Every slot

                                    Hello, world

                                    The first post, in brief.

                                    New

                                    The first post. Cards hold any content; the body is everything without a slot.

                                    Posted on 12 October 2026

                                    Unslotted heading

                                    A leading h3 with no slot is the title, and a p right after it the description.

                                    Hello, again

                                    Styled like the slotted header and description.

                                    The body.

                                    Body only

                                    Just a surface.

                                    al-badge

                                    A small pill for a status or a count.

                                    Variants

                                    Default Published Draft Archived Failed

                                    As a link

                                    Default Secondary Outline Destructive

                                    al-alert

                                    A message box. Write role="alert" (warning, destructive) or role="status" (info, success) yourself: CSS cannot add a role. heading is drawn as the heading. dismissible makes room for the close button that the optional al-alert.js module adds.

                                    Variants

                                    Comments are moderated before they appear. Your post is live. Leaving this page discards your draft. The title must not be empty.

                                    Holding a form's errors

                                    An alert whose only child is an empty ul.errors is not drawn (Alder's <al-alert variant="destructive"><Errors form /></al-alert> before any error). Below: the empty one (hidden), then one with an error.

                                      • That slug is taken.

                                      Without a heading

                                      The default variant is info.

                                      Dismissible (with al-alert.js)

                                      Close me with the button.

                                      al-pagination

                                      Lays out the links the app renders: previous, then "Page N of M" from the attributes, then next. A side with nowhere to go is a <span aria-disabled="true">. Children without a slot go in the middle and replace the generated text.

                                      First page

                                      Previous Next

                                      A middle page

                                      Previous Next

                                      Last page

                                      Previous Next

                                      Your own middle text (the default slot)

                                      Previous Showing 11 to 20 of 48 Next

                                      Page links (the default slot)

                                      Unslotted links are square buttons; aria-current="page" outlines the current one.

                                      Previous 1 2 3 Next

                                      al-stack

                                      Lays its children out in a column (the default) or a wrapping row, with a gap.

                                      Column

                                      One Two Three

                                      Row

                                      One Two Three

                                      A form column: fields stretch, buttons and badges do not

                                        Optional

                                        Gaps: sm, md, lg, xl

                                        One Two Three One Two Three One Two Three One Two Three

                                        A page stack: hidden children add no gap

                                        The hidden input, the empty alert and the closed dialog take no space, so the gap between One and Two is one lg gap.

                                        One

                                          Closed

                                          Not open, so not drawn.

                                          Two

                                          al-page

                                          The content frame: a centred column of a set maximum width. Put one directly in <body>; this demo nests them to compare the widths.

                                          Widths

                                          narrow: at most 40rem

                                          normal (the default): at most 56rem

                                          wide: at most 80rem

                                          Typography

                                          Flow content in a page gets shadcn's typography: headings, paragraphs, links, code, quotes, lists, rules and tables.

                                          A quoted passage.
                                          • First item
                                          • Second item

                                          NameValue
                                          AlphaOne
                                          BetaTwo

                                          The details:

                                          Title
                                          Hello world
                                          Author
                                          Ada Lovelace
                                          Published
                                          25 October 2026

                                          al-dialog

                                          A modal dialog around a native <dialog> that you write: Alder's renderer writes it for you (heading, close button and all), other stacks write it by hand, as here. Opened by commandfor / command="show-modal" on a button. The no-JS form comes first.

                                          Without JavaScript

                                          A link to the dialog's id shows it (:target); the close link # hides it. No script, no invoker commands.

                                          Open (link)

                                          About

                                          Shown by the URL fragment alone.

                                          Sizes

                                          Small

                                          Escape or a backdrop click closes it.

                                          Medium

                                          The default size.

                                          Large

                                          Room for a form or a table.

                                          Dismissible, with actions

                                          The shape Alder emits for dismissible: the close form first, the heading <h2 slot="header"> with an id the dialog's aria-labelledby names, then a slot="description" line in muted text.

                                          Delete this post?

                                          This cannot be undone.

                                          Title
                                          Hello world
                                          Author
                                          Ada Lovelace

                                          al-popover

                                          A floating panel anchored to its invoker. placement picks the side, offset the gap, anchor another anchor by id; the browser flips it when there is no room.

                                          Without JavaScript

                                          popovertarget and the popover attribute are the platform's: no script runs. (Only the placement needs a browser with CSS anchor positioning.)

                                          Opened by popovertarget. Escape or a click outside closes it.

                                          Placements and offsets

                                          Above, with a medium gap. To the left, with a large gap. To the right. Anchored to the Top button, not its invoker.

                                          Title and description

                                          A heading inside the popover is its title and a paragraph its description.

                                          Dimensions

                                          Set the dimensions for the layer.

                                          al-tabs

                                          Tabs backed by a radio group: they work with no script; the script builds the ARIA tabs pattern from them: a tablist of button role=tab (aria-selected, aria-controls, a roving tabindex) before the panels, the labels hidden, tabpanel with aria-labelledby. al-tab holds a label with a radio and its al-panel.

                                          Without JavaScript

                                          The radio group selects the tab and the arrow keys move between tabs; the server writes checked on the radio it picks.

                                          The overview panel. The details panel.

                                          With variant="line" the checked label is underlined; without the script there is no muted pill (the labels and panels share one flex row).

                                          The overview panel. The details panel.

                                          Enhanced

                                          With the script: the ARIA roles and states, Home and End, selected picks the open tab (here the second), and a name on the tab supplies the radio's group.

                                          Three posts. Twelve comments (selected by the server). Settings live here.

                                          Line

                                          variant="line" drops the muted pill and underlines the active tab.

                                          The overview panel. The details panel.

                                          al-toast

                                          A transient message in a corner region. The script shows the region, sets role="status" and closes the toast after timeout.

                                          Without JavaScript

                                          The toast region is a hidden popover until the script shows it, so the server also renders the message in the page as an al-alert:

                                          Post saved.

                                          Enhanced

                                          With the script, each region is shown when its toast connects. On demo/toast.html these are sticky (timeout="0") so you can see all four variants at all four corners; the default timeout is 5000 ms and the toast closes itself. Text or a strong before the first block (div, p, list) is the title and the blocks are the description; a one-line message, even with inline elements, is all title. A toast with no variant has no icon.

                                          Timeout and motion

                                          A toast slides in from its region's edge and, when it closes, slides back out before it is removed (not with reduced motion). This one closes after 3000 ms.

                                          al-tooltip

                                          A text-only hint for the element named by for, shown on hover and focus.

                                          Without JavaScript

                                          The tooltip stays hidden; put the same text in a title on the trigger.

                                          Enhanced

                                          Hover or focus the button: the tooltip is anchored to it, and the button gains aria-describedby. Escape hides it.

                                          Saves without publishing

                                          al-devpanel

                                          Alder's developer bar, as a design-system element: a collapsed bar and an expanded tabbed panel, server-rendered, with monospace code.

                                          Without JavaScript

                                          Open, every section shows (no tab switching); collapsed, only the bar. The server picks with open.

                                          • Rows: 2
                                          SELECT id, title FROM posts WHERE published = 1 ORDER BY id DESC;
                                          Msg: PostSaved

                                          Enhanced and collapsed

                                          With the script, the buttons switch sections and toggle open. This one starts collapsed: click a tab.

                                          SELECT id, title FROM posts;
                                          UPDATE posts SET title = ? WHERE id = ?;
                                          {"page": "home"}

                                          Patched by the server

                                          A server that patches the panel's inner content need not render hidden or aria-selected: the script re-applies the selection. "Patch" below replaces the panel's content with markup that has neither; the chosen section stays the only one showing.

                                          Section A (render 1)
                                          Section B (render 1)