Custom Button Icons
Replace the default thumbs up/down icons with custom SVGs, emoji, or any HTML content to match your brand's visual language.
positiveIcon and negativeIcon take an HTML string. Any SVG, any emoji, anything you can write markup for. Thumbs are just the default.
What you start with
Default Icons
Standard thumbs up/down
Fine for most sites. Wrong for some, which is what the rest of this is about.
SVG icons
Paste the markup straight in.
Heart and broken heart
For anywhere the reaction is felt rather than judged:
Heart Icons
Love it or hate it
new QaidFeedback({
endpoint: '/api/feedback',
positiveIcon: `<svg viewBox="0 0 24 24" fill="currentColor" width="24" height="24">
<path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"/>
</svg>`,
negativeIcon: `<svg viewBox="0 0 24 24" fill="currentColor" width="24" height="24">
<path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"/>
<line x1="4" y1="4" x2="20" y2="20" stroke="currentColor" stroke-width="2"/>
</svg>`,
colors: {
positive: "#ec4899",
negative: "#6b7280"
}
});
Stars
Where readers already expect to be rating something:
Star Icons
Star rating style
new QaidFeedback({
endpoint: '/api/feedback',
positiveIcon: `<svg viewBox="0 0 24 24" fill="currentColor" width="24" height="24">
<path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/>
</svg>`,
negativeIcon: `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="24" height="24">
<path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/>
</svg>`,
colors: {
positive: "#fbbf24",
negative: "#6b7280"
}
});
Check and cross
No emotional reading at all, which suits an approval queue:
Check / X Icons
Clear approval indicators
new QaidFeedback({
endpoint: '/api/feedback',
positiveIcon: `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" width="24" height="24">
<polyline points="20 6 9 17 4 12"/>
</svg>`,
negativeIcon: `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" width="24" height="24">
<line x1="18" y1="6" x2="6" y2="18"/>
<line x1="6" y1="6" x2="18" y2="18"/>
</svg>`,
colors: {
positive: "#22c55e",
negative: "#ef4444"
}
});
Arrows
The convention everyone learned from Reddit and Stack Overflow:
Arrow Icons
Upvote/downvote style
new QaidFeedback({
endpoint: '/api/feedback',
positiveIcon: `<svg viewBox="0 0 24 24" fill="currentColor" width="24" height="24">
<path d="M12 4l-8 8h5v8h6v-8h5l-8-8z"/>
</svg>`,
negativeIcon: `<svg viewBox="0 0 24 24" fill="currentColor" width="24" height="24">
<path d="M12 20l8-8h-5V4H9v8H4l8 8z"/>
</svg>`,
colors: {
positive: "#ff4500",
negative: "#7193ff"
}
});
Emoji
The property takes HTML, and an emoji is a character, so this needs no SVG at all.
Faces
Emoji Faces
Simple and universal
new QaidFeedback({
endpoint: '/api/feedback',
positiveIcon: '<span style="font-size: 24px">😊</span>',
negativeIcon: '<span style="font-size: 24px">😞</span>'
});
Thumbs, but emoji
The default shape rendered in your reader's own emoji font:
Thumbs Emoji
Emoji thumbs
new QaidFeedback({
endpoint: '/api/feedback',
positiveIcon: '<span style="font-size: 24px">👍</span>',
negativeIcon: '<span style="font-size: 24px">👎</span>'
});
Fire and ice
When you want the two ends far apart:
Fire & Ice
Hot or cold reactions
new QaidFeedback({
endpoint: '/api/feedback',
positiveIcon: '<span style="font-size: 24px">🔥</span>',
negativeIcon: '<span style="font-size: 24px">🥶</span>',
colors: {
positive: "#f97316",
negative: "#3b82f6"
}
});
Rocket and crash
Ship it or sink it:
Rocket & Crash
Ship it or sink it
new QaidFeedback({
endpoint: '/api/feedback',
positiveIcon: '<span style="font-size: 24px">🚀</span>',
negativeIcon: '<span style="font-size: 24px">💥</span>',
colors: {
positive: "#8b5cf6",
negative: "#ef4444"
}
});
Icons plus a styled button
The icon and the button it sits in are set separately, so they compose:
Styled Custom Icons
Icons with custom button styling
.cyber-btn {
background: linear-gradient(135deg, #0a0a0a 0%, #1a1a2a 100%);
border: 2px solid currentColor;
border-radius: 8px;
padding: 12px;
transition: all 0.3s ease;
position: relative;
overflow: hidden;
}
.cyber-btn::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, currentColor, transparent);
opacity: 0.1;
transition: left 0.5s ease;
}
.cyber-btn:hover::before {
left: 100%;
}
.cyber-btn:hover {
transform: scale(1.1);
box-shadow: 0 0 20px currentColor;
}
new QaidFeedback({
endpoint: '/api/feedback',
buttonClass: 'cyber-btn',
positiveIcon: `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="24" height="24">
<circle cx="12" cy="12" r="10"/>
<path d="M8 14s1.5 2 4 2 4-2 4-2"/>
<line x1="9" y1="9" x2="9.01" y2="9"/>
<line x1="15" y1="9" x2="15.01" y2="9"/>
</svg>`,
negativeIcon: `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="24" height="24">
<circle cx="12" cy="12" r="10"/>
<path d="M16 16s-1.5-2-4-2-4 2-4 2"/>
<line x1="9" y1="9" x2="9.01" y2="9"/>
<line x1="15" y1="9" x2="15.01" y2="9"/>
</svg>`,
colors: {
positive: "#00ffaa",
negative: "#ff6688"
}
});
On a script tag
data-positive-icon and data-negative-icon take the same strings:
<script
src="https://unpkg.com/@qaiddev/thumbs-embed/dist/embed.js"
data-endpoint="/api/feedback"
data-positive-icon='<span style="font-size: 24px">👍</span>'
data-negative-icon='<span style="font-size: 24px">👎</span>'
></script>
Every quote in the SVG has to be escaped to fit inside an HTML attribute, which gets ugly fast. Past a simple path, use the module form.
Drawing your own
Fill with currentColor and the icon inherits the button's text colour, so one CSS rule moves both. Put explicit width and height on the SVG or sizing gets inconsistent between browsers. Then look at it at 36 pixels, which is what buttonSize: 'small' gives you, because detail that reads at 64 disappears at 36.
And make sure the two icons are opposites. A reader deciding which one they mean should not have to think about it.
Next: color customization, text localization, and theme presets.