VB Project Planning

<story-map>

Horizontal user story map with activity columns and drag-and-drop between columns.

Overview

A web component that renders a horizontal user story map organized by activity columns. Each column contains a <drag-surface> enabling drag-and-drop reorder within a column and transfer between columns. Ideal for sprint planning, backlog grooming, and mapping user activities to deliverable stories.

Attributes

Attribute Type Default Description
src string (URL) — Path to a JSON file containing activity and story data
compact boolean — Reduces column widths, padding, and header font sizes for denser layouts
title string — Optional heading displayed above the story map

Child Attributes

The <story-map> component expects direct <section> children, each defining an activity column. Story items go inside each section.

Section Attributes (Activity Columns)

Attribute Type Default Description
data-activity string — Activity column identifier. Used in event details and as the internal key.
data-activity-label string Title-cased data-activity Display label for the column header. Falls back to a title-cased version of the activity ID.
data-journey-phase string — Optional link to a <user-journey> phase name for cross-referencing

Item Attributes (Story Cards)

Items inside each section become draggable story cards. Use <article> elements for simple text or <user-story> elements for rich story cards.

Attribute Type Description
draggable boolean Must be set to "true" for drag capability
data-id string Stable identifier for the item, included in event details

Column Structure

Each activity column consists of a sticky header and a drag surface area:

  • Header — displays the activity label in uppercase with a count badge showing the number of stories in that column. The badge updates automatically when items are transferred.
  • Drag surface — a <drag-surface> element that holds the story items. All surfaces share the same group identifier, enabling cross-column transfers.
  • Empty state — when a column has no stories, an italic "No stories yet" placeholder appears. The placeholder is removed when an item is dropped in, and re-added when the last item is dragged out.

The columns sit inside a horizontally scrollable container. Each column has a minimum width of 14rem (11rem in compact mode) and a maximum of 22rem, using flex: 1 0 14rem to fill available space while allowing horizontal scroll when columns exceed the viewport.

Drag Interaction

Items can be reordered within a column and transferred between columns:

  • Reorder — drag an item up or down within the same column. Fires a story-map:reorder event with the old and new indices.
  • Transfer — drag an item from one column and drop it onto another. The count badges on both columns update automatically. Fires a story-map:transfer event.
  • Keyboard — <drag-surface> provides keyboard reorder and cross-surface transfer using its built-in keyboard shortcuts.

JSON Loading

Load the entire story map from a JSON file using the src attribute. The component creates activity columns with <user-story> cards automatically.

Using with User Stories

For richer story cards, use <user-story> elements as children instead of plain <article> elements. Add the compact attribute on each story for a tighter layout within the columns.

Events

Event Detail When
story-map:reorder { itemId, activity, oldIndex, newIndex } Fires when an item is reordered within the same activity column
story-map:transfer { itemId, fromActivity, toActivity, newIndex } Fires when an item is dragged from one activity column to another
story-map:ready { activityCount, storyCount } Fires after the component initializes with the total number of activity columns and stories
story-map:upgraded — Once after first connect. Wait for this before assigning .activities from a framework.
story-map:activities-changed { activities, source: 'property' } After .activities assignment.

JavaScript API

<story-map> follows the HTML-first + JS-first dual-mode contract. Reactive consumers (Montane, Lit, Solid, etc.) should wait for story-map:upgraded before assigning .activities.

PropertyTypeDescription
.activities Activity[] Replace the column structure with an array of activities, each with a { name, items: [{ itemId, title, ... }] } shape. Whole-map rebuild on assignment; round-trips through the getter.

Accessibility

  • The scroll container uses role="region" with aria-label="Story map" and is keyboard-focusable via tabindex="0"
  • Each <drag-surface> has an aria-label describing the activity column (e.g., "Discovery stories")
  • A hidden live region with aria-live="polite" announces item transfers between columns
  • Keyboard navigation is provided by the underlying <drag-surface> components
  • Column headers are sticky so the activity label remains visible while scrolling down through long columns
  • Respects prefers-reduced-motion: reduce by disabling scroll behavior transitions
  • Uses container-type: inline-size and stacks columns vertically at narrow viewports (<30rem)
  • Print styles remove sticky positioning, enable wrapping columns, and set break-inside: avoid on columns

Related

↑