Documentation / Guides

Make it yours

STEP 08 / YOUR DESIGN SYSTEM

Make it yours

Pick the surface bundle you need and render its light-DOM contract with your own components, classes, and content. PD rockets supplies interaction behavior, not a required stylesheet. Keep the host tag, stable item IDs, focusable items, and the data-* hooks; style everything around them to fit your product.

If your HTML morph keys elements by DOM id, give each card a stable, board-scoped ID too. That keeps an in-flight animation attached to the same card when another card leaves its lane.

Your server-rendered markup is the design surface. Use your own component classes and CSS custom properties for colors, spacing, and shape; Rocket’s data-* attributes expose the interaction states. There is no mandatory theme or token set.

◈   PD / SIGNAL STATION   ·   LIVE EXPERIMENT 008

Make some waves.

Same Kanban Rocket. A different universe. Drag a transmission or move it with the keyboard.

01 / DISCOVER

Uncharted

02
MAP / 01
AUDIO / 02

END OF CHANNEL

02 / IN MOTION

In orbit

02
FIELD / 03
POST / 04

END OF CHANNEL

03 / COMPLETE

Transmitted

01
BEACON / 05

END OF CHANNEL

Move a card between channels: the demo’s page-owned handler updates its model and morphs confirmed markup over SSE. The moving hologram and destination label are rendered from the two template outlets below. The animated backdrop is a decorative canvas; cards, focus, and drag targets remain HTML. See the canvas source ↗ and theme CSS ↗.

MINI EXPERIMENT / 002

Delete the clichés.

Some SPA tropes deserve the bin. Drag one across, or focus it and use Alt + →.

Trope disposal shortcuts

Focus an item first.

↑ ↓ / j k
Focus a trope
Alt + → / l
Stage a move into the bin
Release Alt / Esc
Dispose / cancel
THE BACKLOG / 05 LEFT
A skeleton for one wordALMOST READY
A loader that never resolvesSTILL LOADING
Duplicated logic that driftsOUT OF SYNC
Megabytes of JavaScriptBUNDLE: HUGE
Rebuilding the browser in JSDIY PLATFORM
Elsa said it best...Drop the baggage.Release to remove it from the model.

This is a rocket-drag-group with a playful destination. The page handler interprets a move to bin as deletion, then returns the remaining HTML over SSE. The poof is decoration; the model change is confirmed by the morph. A short canvas particle burst celebrates the bin without adding anything to the Rocket core. Particle source ↗

Set shortcuts on the host

This sortable list keeps arrow keys and replaces Vim j/k with n/p. It stages reorders with Alt + those same keys. Render the attributes with the host; bindings are resolved when the component connects. The event is an intent: your page applies it and patches the confirmed HTML from its backend.

<section class="project-queue" aria-labelledby="queue-title">
  <h2 id="queue-title">Queue</h2>
  <rocket-sortable-list
    data-key-focus-next="ArrowDown n"
    data-key-focus-previous="ArrowUp p"
    data-key-move-down="Alt+ArrowDown Alt+n"
    data-key-move-up="Alt+ArrowUp Alt+p"
    data-on:rocket-sortable-move="
      $itemId = evt.detail?.['itemId'] ?? null;
      $before = evt.detail?.['before'] ?? null;
      @post('/queue/move')">
    <article class="queue-item" data-sortable-item="item-a" tabindex="0">First task</article>
    <article class="queue-item" data-sortable-item="item-b" tabindex="0">Next task</article>
  </rocket-sortable-list>
</section>

The rocket-sortable-move detail is { itemId, before }; an empty before appends. The example route and signals belong to the page, not the bundle. Set a shortcut attribute to an empty string to disable that intent; see the keyboard reference for the other surfaces and Kanban’s legacy aliases.

Style the states, not the internals

Scope styles under your component class. The host and items are ordinary light-DOM elements; preview and target attributes are styling hooks. By default the floating preview is a clone attached to the document body, so an item class lets it keep your theme outside the host. Give pointer items touch-action: none and a visible keyboard focus state:

.project-queue, .queue-item[data-drag-preview] {
  --queue-accent: var(--color-accent, #256c62);
  --queue-surface: var(--color-surface, #fff);
}
.project-queue rocket-sortable-list {
  display: grid;
  gap: .5rem;
  position: relative;
}
:is(.project-queue [data-sortable-item], .queue-item[data-drag-preview]) {
  position: relative;
  padding: .75rem 1rem;
  border: 1px solid var(--queue-accent);
  border-radius: var(--radius-card, .5rem);
  background: var(--queue-surface);
  cursor: grab;
  touch-action: none;
}
.project-queue [data-sortable-item]:focus-visible {
  outline: 2px solid var(--queue-accent);
  outline-offset: 2px;
}
.project-queue [data-dragging] { opacity: .45; }
.queue-item[data-drag-preview] { box-shadow: 0 12px 24px #0003; }
.project-queue [data-drop-before]::before,
.project-queue rocket-sortable-list[data-drop-end]::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  height: 3px;
  background: var(--queue-accent);
  pointer-events: none;
}
.project-queue [data-drop-before]::before { top: -5px; }
.project-queue rocket-sortable-list[data-drop-end]::after { bottom: -5px; }

Replace the preview or target markup

For richer affordances, render inert <template> fragments with your items and host. A direct-child data-rocket-preview template on an item replaces that item’s floating clone; its class is copied onto the preview wrapper, which moves under document.body. Its size is yours to style; --rocket-source-width and --rocket-source-heightexpose the original dimensions if useful. Direct-child data-rocket-target templates on the host supply target decorations. Rocket inserts their content into a noninteractive [data-rocket-target-indicator] wrapper at the active target for both pointer and keyboard staging. Give target items and containers position: relative so you can position the indicator inside them:

<!-- Inside a server-rendered [data-sortable-item] -->
<template data-rocket-preview class="queue-preview">
  <strong>Moving: First task</strong>
</template>

<!-- Direct children of the rocket-sortable-list host -->
<template data-rocket-target="before">
  <span class="queue-target">Place above</span>
</template>
<template data-rocket-target="end">
  <span class="queue-target">Place at end</span>
</template>
.queue-preview[data-drag-preview] {
  display: grid;
  place-items: center;
  width: max-content;
  min-height: var(--rocket-source-height);
  border: 2px solid var(--color-accent, #256c62);
  border-radius: var(--radius-card, .5rem);
  background: var(--color-surface, #fff);
}
.project-queue [data-rocket-target-indicator] {
  left: 0;
  right: 0;
  color: var(--queue-accent);
}
.project-queue [data-rocket-target-indicator="before"] { top: -1.5rem; }
.project-queue [data-rocket-target-indicator="end"] { bottom: -1.5rem; }
.project-queue .queue-target { display: block; }

Without a preview template Rocket clones the source item. Without a target template the existing data-drop-* states remain available for CSS-only markers like those above. When using a template indicator, replace those pseudo-element marker rules with your indicator styles. Other target kinds are into for tree folders and cell for bento grids; a bare data-rocket-target template can serve every kind on a host. Geometry and the semantic move event still belong to the surface.

Match the affordance to the layout

SurfaceYour markup & layoutRocket styling hooks
Kanban[data-kanban-lane] and [data-kanban-lane-cards] set lane geometry.[data-drop-active], [data-drop-before], [data-drop-end]
Sortable listStyle the host and [data-sortable-item] rows.[data-drop-before] on an item; [data-drop-end] on the host
Drag group[data-drop-list] regions contain [data-drag-item].[data-drop-active], [data-drop-before], [data-drop-end]
Bento[data-bento-grid] provides tracks and rows; tile positions come from your model.[data-bento-target], [data-bento-projecting], [data-bento-resizing]
File tree[data-tree-children] nests rows; honor [hidden] on collapsed folders.[data-tree-before], [data-tree-into], [data-tree-end]

All surfaces expose [data-dragging] on the source, [data-drag-preview] on the detached clone, and [data-key-staging] on the host during keyboard moves. Bento also needs data-columns to match its CSS grid tracks, a fixed grid-auto-rows, and tile grid-column/grid-row styles that match their rendered position data. See the example CSS ↗ for complete layout and state rules.