Welcome to Vanilla Breeze
This bell pulls live notifications from /go/notify/messages — the same contract documented at /docs/concepts/service-contracts/. Static articles like this one are the no-JS / no-backend fallback.
This bell pulls live notifications from /go/notify/messages — the same contract documented at /docs/concepts/service-contracts/. Static articles like this one are the no-JS / no-backend fallback.
Four-quadrant empathy map visualization (Says, Thinks, Does, Feels) with optional flip-to-edit interaction.
A web component that renders a four-quadrant empathy map — Says, Thinks, Does, and Feels — with optional Goals and Pain Points summary rows. Supports slotted HTML content, JSON loading via the src attribute, and a flip-to-edit mode for live editing directly in the browser. Designed for design workshops, sprint planning, and stakeholder presentations.
<empathy-map persona="Sarah Chen" persona-id="persona-sarah"> <h2 slot="title">Product Manager Empathy Map</h2> <p slot="summary">Understanding how Sarah experiences our project dashboard</p> <ul slot="says"> <li>I need everything in one place</li> <li>Can we simplify this workflow?</li> </ul> <ul slot="thinks"> <li>There must be a faster way to track progress</li> <li>Why are these tools so disconnected?</li> </ul> <ul slot="does"> <li>Checks dashboards every morning</li> <li>Exports reports manually as PDF</li> </ul> <ul slot="feels"> <li>frustrated</li> <li>hopeful</li> </ul> <ul slot="goals"> <li>Streamline team communication</li> <li>Track project progress efficiently</li> </ul> <ul slot="pain-points"> <li>Too many disconnected tools</li> <li>Difficulty getting stakeholder buy-in</li> </ul></empathy-map>
| Attribute | Type | Default | Description |
|---|---|---|---|
persona |
string | — | Persona name displayed in the header |
persona-id |
string | — | ID of a <user-persona> element to link to (renders as an anchor) |
src |
string (URL) | — | Path to a JSON file containing quadrant data, goals, and pain points |
editable |
boolean | — | Enables flip-to-edit interaction on each quadrant |
compact |
boolean | — | Reduces padding, font sizes, and icon sizes for denser layouts |
| Slot | Expected Content | Description |
|---|---|---|
title |
<h2> or text |
Map heading displayed in the header. Defaults to "Empathy Map" when omitted. |
summary |
<p> or text |
Brief description shown below the title. |
says |
<ul> or <ol> |
Quotes and statements the persona makes. Displayed in the top-left quadrant with a blue accent. |
thinks |
<ul> or <ol> |
Internal thoughts and beliefs. Displayed in the top-right quadrant with a purple accent. |
does |
<ul> or <ol> |
Observable actions and behaviors. Displayed in the bottom-left quadrant with an amber accent. |
feels |
<ul> or <ol> |
Emotional states. Items matching EMOTION_META keys get automatic emoji and color treatment. Displayed in the bottom-right quadrant with a red accent. |
goals |
<ul> or <ol> |
Optional goals summary displayed below the quadrant grid |
pain-points |
<ul> or <ol> |
Optional pain points summary displayed below the quadrant grid |
Content values (title, summary) are provided as named slots. State attributes (persona, persona-id) remain on the element.
Add the editable attribute to enable flip-to-edit on each quadrant. Each quadrant header displays an edit button that flips the card to reveal a textarea. Enter one item per line, then press the "Done" button or hit Escape to save and flip back.
<empathy-map persona="Alex Rivera" editable> <h2 slot="title">Workshop Empathy Map</h2></empathy-map>
When a quadrant is opened for editing, the front face becomes inert and the textarea receives focus. On close, the component updates its internal .quadrants data, re-renders the front face content, and dispatches an empathy-map:update event with the changed quadrant name and items.
You can also control editing programmatically:
const map = document.querySelector('empathy-map'); // Open the "thinks" quadrant for editingmap.editQuadrant('thinks'); // Close and savemap.closeQuadrant('thinks');
Load quadrant data from a JSON file via the src attribute, or set the .quadrants property programmatically. The JSON schema supports top-level metadata plus quadrant arrays, goals, and pain points.
{ "title": "Product Manager Empathy Map", "persona": "Sarah Chen", "personaId": "persona-sarah", "summary": "Understanding daily workflow frustrations", "quadrants": { "says": ["I need everything in one place", "Can we simplify this?"], "thinks": ["There must be a faster way", "Why so disconnected?"], "does": ["Checks dashboards every morning", "Exports reports as PDF"], "feels": ["frustrated", "hopeful"] }, "goals": ["Streamline communication", "Track progress efficiently"], "painPoints": ["Too many tools", "Stakeholder buy-in is hard"]}
const map = document.querySelector('empathy-map'); map.quadrants = { says: ['I need everything in one place'], thinks: ['There must be a better way'], does: ['Checks dashboards every morning'], feels: ['frustrated', 'curious'],}; map.goals = ['Streamline communication'];map.painPoints = ['Too many disconnected tools'];
Items in the "feels" quadrant are checked against the EMOTION_META dictionary. When an item's text matches a known emotion key (case-insensitive), it renders as a colored pill with the corresponding emoji. This is the same emotion vocabulary used by <user-journey>.
| Emotion Key | Emoji | Color |
|---|---|---|
delighted |
😄 | #16a34a |
satisfied |
😊 | #22c55e |
hopeful |
🙂 | #84cc16 |
curious |
🤔 | #eab308 |
neutral |
😐 | #94a3b8 |
uncertain |
😕 | #f97316 |
confused |
😵 | #fb923c |
frustrated |
😤 | #ef4444 |
angry |
😠 | #dc2626 |
Items that do not match a known emotion key render as plain text. You can mix recognized emotions with freeform text in the same quadrant.
| Variable | Default | Description |
|---|---|---|
--empathy-map-bg |
#ffffff |
Background color (used for editor and button backgrounds) |
--empathy-map-text |
#1a1a1a |
Primary text color |
--empathy-map-border |
#e0e0e0 |
Card border and grid gap color |
--empathy-map-muted |
#666666 |
Secondary/muted text for labels and summary |
--empathy-map-accent |
#0066cc |
Accent color for focus rings and interactive elements |
--empathy-map-card |
#f8f9fa |
Card and quadrant background color |
--empathy-map-radius |
16px |
Outer card border radius |
--empathy-map-says |
#3b82f6 |
Says quadrant accent color (top border) |
--empathy-map-thinks |
#8b5cf6 |
Thinks quadrant accent color (top border) |
--empathy-map-does |
#f59e0b |
Does quadrant accent color (top border) |
--empathy-map-feels |
#ef4444 |
Feels quadrant accent color (top border) |
| Event | Detail | When |
|---|---|---|
empathy-map:ready |
{ title, persona } |
Fires after the component finishes rendering (including after JSON load) |
empathy-map:update |
{ quadrant, items } |
Fires when a quadrant is closed after editing, with the quadrant name and updated items array |
<article> element for semantic grouping<section> with a visible heading for screen reader navigationaria-hidden="true"aria-label of "Edit [quadrant name]"inert and focus moves to the textareaaria-label describing its purposeprefers-reduced-motion: reduce by disabling flip transitionscontainer-type: inline-size and stacks to a single column at narrow viewports (<500px)<user-persona> — Persona cards linked via persona-id<user-story> — Agile story cards that complement empathy maps<user-journey> — Journey maps using the same emotion vocabulary<impact-effort> — Prioritization matrix for discovered pain points<story-map> — Horizontal story mapping for sprint planning