Skip to content

Components / Sections

Services List

What a studio or a freelancer does, as numbered rows at display size that open one at a time: each row names a service, and opens to a short text beside the list of deliverables. Every row is a native <details> (the browser owns the opening, the keyboard and the one-open rule through the name attribute), the height animates through ::details-content, and the name underlines on hover with UnderlineHover. Zero JavaScript of its own.

Live demo

Sample services

What an imaginary studio does

Brand identity

A name, a mark and the rules that hold them together, for a company that is new or has outgrown its look.

Deliverables

  • Logo and mark
  • Type and colour
  • Guidelines
Websites

Sites designed and built by one team, from the first sketch to the code that ships.

Deliverables

  • Design system
  • Astro build
  • Content model
Product design

Screens for an app or a tool, drawn with the people who will use them and handed over as working components.

Deliverables

  • Flows
  • Interface
  • Components
Motion

The logo in motion, a product film, the interface itself: motion that says one thing each time.

Deliverables

  • Motion identity
  • Product film
  • Interaction specs

Live, from the library itself, at full size: scroll, hover, navigate away and back. The demo is never gated.

Variants · each row writes the attribute the prop writes; the section's own CSS answers

tone
density

Measured

JavaScript of its own

0 B

CSS 10.4 kB raw including the base tokens. Measured from a production build, and again in CI for every change that can move it.

Browser support

Baseline · newly available

Chrome 131 · Firefox 143 · Safari 18.4; needs details-content, details-name. Elsewhere: without ::details-content a row opens at once, without the height animation; without the name attribute (Firefox before 130) several rows can be open together.

Install Pro

The demo above is never gated; the source is. With a key in components.json (see account), the registry serves it like any other item:

terminal
npx shadcn@latest add @moonarc-pro/services-list
src/pages/index.astro
---
import ServicesList from '@/components/moonarc/pro/ServicesList.astro';
---
<ServicesList
  headline="Services"
  services={[
    { title: 'Brand identity', body: 'A name, a mark and the rules that hold them together, for a company that is new or has outgrown its look.', deliverables: ['Logo and mark', 'Type and colour', 'Brand guidelines'] },
    { title: 'Websites', body: 'Sites designed and built in one team, from the first sketch to the code that ships.', deliverables: ['Design system', 'Astro build', 'Content model'] },
    { title: 'Motion', body: 'Animation for screens and campaigns: the logo in motion, product films, the interface itself.', deliverables: ['Motion identity', 'Product film', 'Interaction specs'] },
  ]}
  open={0}
/>

Without a key the registry answers 401 with an upgrade message. Everything this section composes is free: underline-hover.

Props

PropTypeDefaultDescription
services{ title: string; body: string; deliverables?: string[] }[]noneThe rows, in order: a name, a short paragraph, and what the client receives, one line each.
headlinestringnoneThe section's heading. Slot "headline" wins.
eyebrowstringnoneA short line above the headline, in mono. Slot "eyebrow" wins.
copystringnoneA paragraph under the headline. Slot "copy" wins.
level1 | 22Heading level of the headline: 2 under a page's h1, 1 when the list is the page's own heading.
exclusivebooleantrueOne row open at a time: opening one closes the others, through the details name attribute (no script).
opennumbernoneIndex of the row open on load; unset, all are closed.
deliverablesLabelstring'Deliverables'The small title over each row's deliverables.
numberedbooleantruePrint 01, 02 … before each name, in mono. The numbers are aria-hidden: the order is the list's own.
tone'surface' | 'muted' | 'ink' | 'brand'unset (paints nothing)The ground: the page surface, a muted band, an always-dark ink panel, or a deep brand panel. The hairlines follow the tone's --border, and an open row's plus inverts in the tone's own pair.
density'compact' | 'cozy' | 'roomy''cozy'Block padding and the rows' height ×0.8 / ×1 / ×1.25 through --ma-density.

Theming and overrides

The section reads the theme contract (shadcn's variable names with the base tokens as fallback), so a pasted theme or one --ma-brand recolours it. Its class names are the override surface and stay stable; a named slot replaces the matching prop with your own markup.

Classes

.ma-services.ma-services__actions.ma-services__bar--v.ma-services__body.ma-services__copy.ma-services__deliver.ma-services__eyebrow.ma-services__head.ma-services__headline.ma-services__icon.ma-services__index.ma-services__inner.ma-services__item.ma-services__items.ma-services__label.ma-services__list.ma-services__summary.ma-services__text.ma-services__title

Slots

slot="eyebrow"slot="headline"slot="copy"slot="actions"slot="aside"

Reduced motion

Rows open and close at once; the plus turns into a minus without the transition, and the underline appears without its sweep.

With ClientRouter

Native <details>; nothing to rebind. A row open on the page a reader leaves is closed again on the next load, as the server rendered it.

Why it is built this way

Replaces: Services sections (Framer studio templates) · Accordion services (Aceternity) · Services list (Relume). See the migration table.

Zero JavaScript?

For this one, yes. The browser animates the height.

Keyboard?

Native: Tab, Enter, Space.

One at a time?

details name=, also native.

Native <details> items whose height animates open and closed, with an optional one-at-a-time rule the browser enforces.

newly · Chrome 131 · Firefox 143 · Safari 18.4click

A link underline that enters from the left on hover and leaves to the right, so the exit continues the entrance instead of rewinding it.

every browserhover

Questions people actually ask

Short answers. The long ones are in the docs.

Is it really zero JS?

For 83 of 125, yes, measured from a build.

Does it survive View Transitions?

Yes, verified on Astro 5, 6 and 7.

Do I need Tailwind?

No.

FAQ

Pro

A heading and lead beside a native accordion: one question open at a time, heights animated by the browser, keyboard and screen reader handled by <details>.

newly · Chrome 131 · Firefox 143 · Safari 18.4scrollclick

A vertical timeline: the line draws itself down the page in step with the scroll, each step revealing from the line's side as it is reached, markers numbered or dated.

Chrome 115 · not Firefox · Safari 26scroll

Also: view transitions · how costs are measured · browser support · accessibility policy · five-minute setup · MCP for agents · this page as Markdown