empathy-map
Four-quadrant empathy map visualization (Says, Thinks, Does, Feels) with optional flip-to-edit interaction.
Overview
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 title="Product Manager Empathy Map" persona="Sarah Chen" persona-id="persona-sarah" summary="Understanding how Sarah experiences our project dashboard"> <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>
Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
title |
string | "Empathy Map" |
Map heading displayed in the header |
persona |
string | — | Persona name displayed in the header |
persona-id |
string | — | ID of a <user-persona> element to link to (renders as an anchor) |
summary |
string | — | Brief description shown below the title |
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 |
Slots
| Slot | Expected Content | Description |
|---|---|---|
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 |
Scalar attributes (title, persona, summary) can also be provided as named slots for SSR-friendly authoring. Attributes take priority when both are present.
Editable Mode
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 title="Workshop Empathy Map" persona="Alex Rivera" editable></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');
Data Mode
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'];
Emotion Recognition
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.
CSS Custom Properties
| 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) |
Events
| 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 |
Accessibility
- The outer card renders as an
<article>element for semantic grouping - Each quadrant is a
<section>with a visible heading for screen reader navigation - Decorative quadrant icons use
aria-hidden="true" - In editable mode, the edit button has an
aria-labelof "Edit [quadrant name]" - When a quadrant flips to edit, the front face becomes
inertand focus moves to the textarea - The textarea has an
aria-labeldescribing its purpose - Respects
prefers-reduced-motion: reduceby disabling flip transitions - Uses
container-type: inline-sizeand stacks to a single column at narrow viewports (<500px) - Print styles hide edit buttons and editor faces for clean print output
Related
<user-persona>— Persona cards linked viapersona-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- UX Planning Pack — loads all six UX components together