Skip to content
← Bubble Chart
Edit Bubble Chart
Name
Also known as (comma separated)
Brief definition
Scatter plot using bubble size as another dimension.
Notes
Tier
Core
Useful
Reference
Deleted
Controls schema (JSON array)
[ { "id": "emphasis", "type": "select", "label": "Featured bubble size", "default": "medium", "options": [ "small", "medium", "large" ] }, { "id": "accent", "type": "color", "label": "Colour", "default": "#D9C8F0", "presets": [ "#A8E6C1", "#F5C2E0", "#BFD9F2", "#D9C8F0", "#E8A020", "#241430" ] }, { "id": "showLabels", "type": "toggle", "label": "Show value labels", "default": true }, { "id": "bubbleCount", "type": "select", "label": "Bubble count", "default": "5", "options": [ "3", "4", "5" ] } ]
Templates (JSON object keyed by format)
{ "html": "<figure class=\"bubble-chart-demo bubble-chart-demo--emphasis-{{emphasis}} bubble-chart-demo--count-{{bubbleCount}}\" style=\"--accent:{{accent}};\">\n <figcaption class=\"bubble-chart-demo__title\">Deal value by product</figcaption>\n <svg class=\"bubble-chart-demo__svg\" viewBox=\"0 0 300 150\" role=\"img\" aria-label=\"Bubble chart plotting product engagement against reach, bubble size shows deal value, featured product sized {{emphasis}}\">\n <g aria-hidden=\"true\">\n <line x1=\"30\" y1=\"10\" x2=\"30\" y2=\"130\" class=\"bubble-chart-demo__axisline\" />\n <line x1=\"30\" y1=\"130\" x2=\"300\" y2=\"130\" class=\"bubble-chart-demo__axisline\" />\n <text x=\"26\" y=\"18\" class=\"bubble-chart-demo__tick\" text-anchor=\"end\">40k</text>\n <text x=\"26\" y=\"74\" class=\"bubble-chart-demo__tick\" text-anchor=\"end\">20k</text>\n <text x=\"26\" y=\"130\" class=\"bubble-chart-demo__tick\" text-anchor=\"end\">0k</text>\n <text x=\"165\" y=\"146\" class=\"bubble-chart-demo__axislabel\" text-anchor=\"middle\">Engagement (visits, k)</text>\n </g>\n <g class=\"bubble-chart-demo__bubble bubble-chart-demo__bubble--b\">\n <circle cx=\"120\" cy=\"60\" r=\"14\" class=\"bubble-chart-demo__circle\" />\n {{#if showLabels}}<text x=\"120\" y=\"40\" class=\"bubble-chart-demo__value\">$14k</text>{{/if}}\n </g>\n <g class=\"bubble-chart-demo__bubble bubble-chart-demo__bubble--c\">\n <circle cx=\"180\" cy=\"100\" r=\"10\" class=\"bubble-chart-demo__circle\" />\n {{#if showLabels}}<text x=\"180\" y=\"84\" class=\"bubble-chart-demo__value\">$10k</text>{{/if}}\n </g>\n <g class=\"bubble-chart-demo__bubble bubble-chart-demo__bubble--d\">\n <circle cx=\"230\" cy=\"50\" r=\"18\" class=\"bubble-chart-demo__circle\" />\n {{#if showLabels}}<text x=\"230\" y=\"26\" class=\"bubble-chart-demo__value\">$18k</text>{{/if}}\n </g>\n <g class=\"bubble-chart-demo__bubble bubble-chart-demo__bubble--e\">\n <circle cx=\"270\" cy=\"120\" r=\"8\" class=\"bubble-chart-demo__circle\" />\n {{#if showLabels}}<text x=\"270\" y=\"106\" class=\"bubble-chart-demo__value\">$8k</text>{{/if}}\n </g>\n <g class=\"bubble-chart-demo__bubble bubble-chart-demo__bubble--a-small\">\n <circle cx=\"60\" cy=\"110\" r=\"8\" class=\"bubble-chart-demo__circle bubble-chart-demo__circle--featured\" />\n {{#if showLabels}}<text x=\"60\" y=\"96\" class=\"bubble-chart-demo__value\">$20k</text>{{/if}}\n </g>\n <g class=\"bubble-chart-demo__bubble bubble-chart-demo__bubble--a-medium\">\n <circle cx=\"60\" cy=\"110\" r=\"16\" class=\"bubble-chart-demo__circle bubble-chart-demo__circle--featured\" />\n {{#if showLabels}}<text x=\"60\" y=\"88\" class=\"bubble-chart-demo__value\">$20k</text>{{/if}}\n </g>\n <g class=\"bubble-chart-demo__bubble bubble-chart-demo__bubble--a-large\">\n <circle cx=\"60\" cy=\"110\" r=\"26\" class=\"bubble-chart-demo__circle bubble-chart-demo__circle--featured\" />\n {{#if showLabels}}<text x=\"60\" y=\"78\" class=\"bubble-chart-demo__value\">$20k</text>{{/if}}\n </g>\n </svg>\n <div class=\"bubble-chart-demo__legend\">\n <span class=\"bubble-chart-demo__legend-item\"><svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" aria-hidden=\"true\"><circle cx=\"5\" cy=\"5\" r=\"3\" class=\"bubble-chart-demo__legend-dot\" /></svg>Low deal value</span>\n <span class=\"bubble-chart-demo__legend-item\"><svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" aria-hidden=\"true\"><circle cx=\"8\" cy=\"8\" r=\"6\" class=\"bubble-chart-demo__legend-dot\" /></svg>Medium deal value</span>\n <span class=\"bubble-chart-demo__legend-item\"><svg width=\"22\" height=\"22\" viewBox=\"0 0 22 22\" aria-hidden=\"true\"><circle cx=\"11\" cy=\"11\" r=\"9\" class=\"bubble-chart-demo__legend-dot\" /></svg>High deal value</span>\n </div>\n</figure>\n<style>\n.bubble-chart-demo { font: 12px system-ui, sans-serif; color: #241430; background: #FAF7F2; padding: 16px; border: 1.5px solid #24143022; border-radius: 12px; box-sizing: border-box; max-width: 640px; }\n.bubble-chart-demo__title { font-size: 13px; font-weight: 600; margin: 0 0 10px; }\n.bubble-chart-demo__svg { width: 100%; display: block; overflow: visible; }\n.bubble-chart-demo__axisline { stroke: #24143055; stroke-width: 1; }\n.bubble-chart-demo__tick { font-size: 9px; fill: #24143099; }\n.bubble-chart-demo__axislabel { font-size: 9px; fill: #24143099; }\n.bubble-chart-demo__circle { fill: var(--accent); fill-opacity: .55; stroke: var(--accent); stroke-width: 1.5; }\n.bubble-chart-demo__value { font-size: 9px; fill: #241430; text-anchor: middle; }\n.bubble-chart-demo__bubble--a-small, .bubble-chart-demo__bubble--a-medium, .bubble-chart-demo__bubble--a-large { display: none; }\n.bubble-chart-demo--emphasis-small .bubble-chart-demo__bubble--a-small,\n.bubble-chart-demo--emphasis-medium .bubble-chart-demo__bubble--a-medium,\n.bubble-chart-demo--emphasis-large .bubble-chart-demo__bubble--a-large { display: block; }\n.bubble-chart-demo--count-3 .bubble-chart-demo__bubble--d,\n.bubble-chart-demo--count-3 .bubble-chart-demo__bubble--e,\n.bubble-chart-demo--count-4 .bubble-chart-demo__bubble--e { display: none; }\n.bubble-chart-demo__legend { display: flex; gap: 14px; margin-top: 10px; flex-wrap: wrap; }\n.bubble-chart-demo__legend-item { display: inline-flex; align-items: center; gap: 5px; font-size: 11px; }\n.bubble-chart-demo__legend-dot { fill: var(--accent); fill-opacity: .55; stroke: var(--accent); stroke-width: 1.5; }\n</style>", "tailwind": "<figure class=\"bubble-chart-tw bubble-chart-tw--emphasis-{{emphasis}} bubble-chart-tw--count-{{bubbleCount}} max-w-[640px] p-4 border-[1.5px] border-[#24143022] rounded-xl box-border font-sans text-[#241430] bg-[#FAF7F2]\" style=\"--accent:{{accent}};\">\n <figcaption class=\"text-[13px] font-semibold mb-2.5\">Deal value by product</figcaption>\n <svg class=\"w-full block\" style=\"overflow:visible;\" viewBox=\"0 0 300 150\" role=\"img\" aria-label=\"Bubble chart plotting product engagement against reach, bubble size shows deal value, featured product sized {{emphasis}}\">\n <g aria-hidden=\"true\">\n <line x1=\"30\" y1=\"10\" x2=\"30\" y2=\"130\" stroke=\"#24143055\" />\n <line x1=\"30\" y1=\"130\" x2=\"300\" y2=\"130\" stroke=\"#24143055\" />\n <text x=\"26\" y=\"18\" font-size=\"9\" fill=\"#24143099\" text-anchor=\"end\">40k</text>\n <text x=\"26\" y=\"74\" font-size=\"9\" fill=\"#24143099\" text-anchor=\"end\">20k</text>\n <text x=\"26\" y=\"130\" font-size=\"9\" fill=\"#24143099\" text-anchor=\"end\">0k</text>\n <text x=\"165\" y=\"146\" font-size=\"9\" fill=\"#24143099\" text-anchor=\"middle\">Engagement (visits, k)</text>\n </g>\n <g class=\"bubble-chart-tw__bubble bubble-chart-tw__bubble--b\">\n <circle cx=\"120\" cy=\"60\" r=\"14\" class=\"bubble-chart-tw__circle\" />\n {{#if showLabels}}<text x=\"120\" y=\"40\" class=\"bubble-chart-tw__value\">$14k</text>{{/if}}\n </g>\n <g class=\"bubble-chart-tw__bubble bubble-chart-tw__bubble--c\">\n <circle cx=\"180\" cy=\"100\" r=\"10\" class=\"bubble-chart-tw__circle\" />\n {{#if showLabels}}<text x=\"180\" y=\"84\" class=\"bubble-chart-tw__value\">$10k</text>{{/if}}\n </g>\n <g class=\"bubble-chart-tw__bubble bubble-chart-tw__bubble--d\">\n <circle cx=\"230\" cy=\"50\" r=\"18\" class=\"bubble-chart-tw__circle\" />\n {{#if showLabels}}<text x=\"230\" y=\"26\" class=\"bubble-chart-tw__value\">$18k</text>{{/if}}\n </g>\n <g class=\"bubble-chart-tw__bubble bubble-chart-tw__bubble--e\">\n <circle cx=\"270\" cy=\"120\" r=\"8\" class=\"bubble-chart-tw__circle\" />\n {{#if showLabels}}<text x=\"270\" y=\"106\" class=\"bubble-chart-tw__value\">$8k</text>{{/if}}\n </g>\n <g class=\"bubble-chart-tw__bubble bubble-chart-tw__bubble--a-small\">\n <circle cx=\"60\" cy=\"110\" r=\"8\" class=\"bubble-chart-tw__circle bubble-chart-tw__circle--featured\" />\n {{#if showLabels}}<text x=\"60\" y=\"96\" class=\"bubble-chart-tw__value\">$20k</text>{{/if}}\n </g>\n <g class=\"bubble-chart-tw__bubble bubble-chart-tw__bubble--a-medium\">\n <circle cx=\"60\" cy=\"110\" r=\"16\" class=\"bubble-chart-tw__circle bubble-chart-tw__circle--featured\" />\n {{#if showLabels}}<text x=\"60\" y=\"88\" class=\"bubble-chart-tw__value\">$20k</text>{{/if}}\n </g>\n <g class=\"bubble-chart-tw__bubble bubble-chart-tw__bubble--a-large\">\n <circle cx=\"60\" cy=\"110\" r=\"26\" class=\"bubble-chart-tw__circle bubble-chart-tw__circle--featured\" />\n {{#if showLabels}}<text x=\"60\" y=\"78\" class=\"bubble-chart-tw__value\">$20k</text>{{/if}}\n </g>\n </svg>\n <div class=\"flex gap-3.5 mt-2.5 flex-wrap\">\n <span class=\"inline-flex items-center gap-1 text-[11px]\"><svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" aria-hidden=\"true\"><circle cx=\"5\" cy=\"5\" r=\"3\" style=\"fill:{{accent}};fill-opacity:.55;stroke:{{accent}};stroke-width:1.5;\" /></svg>Low deal value</span>\n <span class=\"inline-flex items-center gap-1 text-[11px]\"><svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" aria-hidden=\"true\"><circle cx=\"8\" cy=\"8\" r=\"6\" style=\"fill:{{accent}};fill-opacity:.55;stroke:{{accent}};stroke-width:1.5;\" /></svg>Medium deal value</span>\n <span class=\"inline-flex items-center gap-1 text-[11px]\"><svg width=\"22\" height=\"22\" viewBox=\"0 0 22 22\" aria-hidden=\"true\"><circle cx=\"11\" cy=\"11\" r=\"9\" style=\"fill:{{accent}};fill-opacity:.55;stroke:{{accent}};stroke-width:1.5;\" /></svg>High deal value</span>\n </div>\n</figure>\n<style>\n.bubble-chart-tw__circle, [class*=\"bubble-chart-tw__circle\"] { fill: var(--accent); fill-opacity: .55; stroke: var(--accent); stroke-width: 1.5; }\n.bubble-chart-tw__value { font-size: 9px; fill: #241430; text-anchor: middle; }\n.bubble-chart-tw__bubble--a-small, .bubble-chart-tw__bubble--a-medium, .bubble-chart-tw__bubble--a-large { display: none; }\n.bubble-chart-tw--emphasis-small .bubble-chart-tw__bubble--a-small,\n.bubble-chart-tw--emphasis-medium .bubble-chart-tw__bubble--a-medium,\n.bubble-chart-tw--emphasis-large .bubble-chart-tw__bubble--a-large { display: block; }\n.bubble-chart-tw--count-3 .bubble-chart-tw__bubble--d,\n.bubble-chart-tw--count-3 .bubble-chart-tw__bubble--e,\n.bubble-chart-tw--count-4 .bubble-chart-tw__bubble--e { display: none; }\n</style>", "react": "export function BubbleChart({\n emphasis = \"{{emphasis}}\",\n accent = \"{{accent}}\",\n showLabels = {{showLabels}},\n bubbleCount = \"{{bubbleCount}}\",\n}) {\n const emphasisRadii = { small: 8, medium: 16, large: 26 };\n const aR = emphasisRadii[emphasis] ?? 16;\n const aX = 60, aY = 110;\n const rest = [\n { id: \"b\", x: 120, y: 60, r: 14, val: \"$14k\", labelY: 40 },\n { id: \"c\", x: 180, y: 100, r: 10, val: \"$10k\", labelY: 84 },\n { id: \"d\", x: 230, y: 50, r: 18, val: \"$18k\", labelY: 26 },\n { id: \"e\", x: 270, y: 120, r: 8, val: \"$8k\", labelY: 106 },\n ].slice(0, Number(bubbleCount) - 1);\n const circleStyle = { fill: accent, fillOpacity: 0.55, stroke: accent, strokeWidth: 1.5 };\n return (\n <figure style={{ font: \"12px system-ui, sans-serif\", color: \"#241430\", background: \"#FAF7F2\", padding: 16, border: \"1.5px solid #24143022\", borderRadius: 12, boxSizing: \"border-box\", maxWidth: 640 }}>\n <figcaption style={{ fontSize: 13, fontWeight: 600, marginBottom: 10 }}>Deal value by product</figcaption>\n <svg viewBox=\"0 0 300 150\" style={{ width: \"100%\", display: \"block\", overflow: \"visible\" }} role=\"img\" aria-label={\"Bubble chart plotting product engagement against reach, bubble size shows deal value, featured product sized \" + emphasis}>\n <g aria-hidden=\"true\">\n <line x1=\"30\" y1=\"10\" x2=\"30\" y2=\"130\" stroke=\"#24143055\" />\n <line x1=\"30\" y1=\"130\" x2=\"300\" y2=\"130\" stroke=\"#24143055\" />\n <text x=\"26\" y=\"18\" fontSize=\"9\" fill=\"#24143099\" textAnchor=\"end\">40k</text>\n <text x=\"26\" y=\"74\" fontSize=\"9\" fill=\"#24143099\" textAnchor=\"end\">20k</text>\n <text x=\"26\" y=\"130\" fontSize=\"9\" fill=\"#24143099\" textAnchor=\"end\">0k</text>\n <text x=\"165\" y=\"146\" fontSize=\"9\" fill=\"#24143099\" textAnchor=\"middle\">Engagement (visits, k)</text>\n </g>\n {rest.map((b) => (\n <g key={b.id}>\n <circle cx={b.x} cy={b.y} r={b.r} style={circleStyle} />\n {showLabels && <text x={b.x} y={b.labelY} fontSize=\"9\" fill=\"#241430\" textAnchor=\"middle\">{b.val}</text>}\n </g>\n ))}\n <g>\n <circle cx={aX} cy={aY} r={aR} style={circleStyle} />\n {showLabels && <text x={aX} y={aY - aR - 6} fontSize=\"9\" fill=\"#241430\" textAnchor=\"middle\">$20k</text>}\n </g>\n </svg>\n <div style={{ display: \"flex\", gap: 14, marginTop: 10, flexWrap: \"wrap\" }}>\n <span style={{ display: \"inline-flex\", alignItems: \"center\", gap: 5, fontSize: 11 }}>\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" aria-hidden=\"true\"><circle cx=\"5\" cy=\"5\" r=\"3\" style={circleStyle} /></svg>Low deal value\n </span>\n <span style={{ display: \"inline-flex\", alignItems: \"center\", gap: 5, fontSize: 11 }}>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" aria-hidden=\"true\"><circle cx=\"8\" cy=\"8\" r=\"6\" style={circleStyle} /></svg>Medium deal value\n </span>\n <span style={{ display: \"inline-flex\", alignItems: \"center\", gap: 5, fontSize: 11 }}>\n <svg width=\"22\" height=\"22\" viewBox=\"0 0 22 22\" aria-hidden=\"true\"><circle cx=\"11\" cy=\"11\" r=\"9\" style={circleStyle} /></svg>High deal value\n </span>\n </div>\n </figure>\n );\n}" }
Save
History