List
Free · MITHeadless, accessible, and styled entirely through the attribute surface below — bring your own CSS system, or start from the reference theme.
Install
Without a flag you get no styling at all — plain HTML carrying the attribute surface below. --theme copies the same theme in two dialects;--bridge lumos re-points either one onto Lumos for Astro's tokens (it needs a theme to re-point, and Lumos itself, already in your project).
Unstyled — behavior only, you write the CSS
npx astrocraft-ui add display/listPlain-CSS theme — no build step
npx astrocraft-ui add display/list --theme cssTailwind theme — needs Tailwind v4
npx astrocraft-ui add display/list --theme tailwindPlain-CSS theme, re-pointed onto Lumos tokens
npx astrocraft-ui add display/list --theme css --bridge lumosTailwind theme, re-pointed onto Lumos tokens
npx astrocraft-ui add display/list --theme tailwind --bridge lumosLive demo
List
Marker styles, a styled marker via marker:* at the call site, the horizontal dot-separated inline list, and icon items through ListItem's icon slot.
- Astro islands
- Tailwind tokens
- Zero-JS first
- Install dependencies
- Set the site URL
- Ship it
- Primary markers
- Same text tokens
- One class at the call site
- Terms
- Privacy
- Cookies
- Licenses
- Unlimited projects
- Custom domains
- Recolored via the icon
Attribute surface
With no class-merging machinery, these attributes are the whole extension point. State is a data-attribute or a native attribute; visibility is the hiddenattribute. Generated from source by pnpm slots.
| Component | Slots | Variants | Runtime state | Native state |
|---|---|---|---|---|
| `List.astro` | `list` | `data-marker`: `none` · `disc` · `decimal` `data-orientation`: `vertical` · `horizontal` | — | — |
| `ListItem.astro` | `list-item` `list-item-icon` | `data-icon`: `true` when set | — | — |
Source
What the command copies — 3 files, alias-free so the copy lands standing alone. This is the whole component; there is nothing else.
---
// src/components/ui/display/list/List.astro — headless primitive (see ../../README.md).
// Static styled list. `marker` picks the style and is the one variant that changes the ELEMENT:
// `decimal` renders an <ol>, everything else a <ul> — that is structure, so it stays here rather
// than becoming a theme concern. `orientation="horizontal"` is the inline/dot-separated shape; the
// separator dot itself is a `li + li::before` the theme draws, so items stay plain <li>s.
import type { HTMLAttributes } from "astro/types";
type Props = HTMLAttributes<"ul"> & {
marker?: "none" | "disc" | "decimal";
orientation?: "vertical" | "horizontal";
};
const { marker = "none", orientation = "vertical", class: className, ...rest } = Astro.props;
const Tag = marker === "decimal" ? "ol" : "ul";
---
<Tag
class={className}
data-slot="list"
data-marker={marker}
data-orientation={orientation}
{...rest}
>
<slot />
</Tag>
---
// src/components/ui/display/list/ListItem.astro — List compound part (see ../../README.md).
// Plain <li>. Drop an icon in the `icon` slot (the "checked list" pattern) and the item reports
// `data-icon="true"` so a theme can switch it to a row — the switch is slot-driven, never a prop,
// because `icon={false}` alongside a provided slot would be a silently wrong state.
import type { HTMLAttributes } from "astro/types";
type Props = HTMLAttributes<"li">;
const { class: className, ...rest } = Astro.props;
const hasIcon = Astro.slots.has("icon");
---
<li class={className} data-slot="list-item" data-icon={hasIcon ? "true" : undefined} {...rest}>
{
hasIcon && (
<span data-slot="list-item-icon" aria-hidden="true">
<slot name="icon" />
</span>
)
}
<slot />
</li>
import List from "./List.astro";
import ListItem from "./ListItem.astro";
export { List, ListItem };
export default List;
What you get
The component source, copied into your project by npx astrocraft-ui add display/list — no package dependency, no CSS to fight. Whatever the paid blocks compose, this is it.