From emojis to elegance: revamping reaction buttons

Previously on the CogitActive Saga:
The reaction buttons are in place, integrated and functional. But just look at them. This isn’t over—not even close.

As I close in on what will—hopefully—be the final piece of the puzzle, let me take a moment to catch up with those who haven’t followed this ongoing mini-series. Restoring my reaction system has been anything but straightforward. Finding a viable replacement for the abandoned Reaction Buttons plugin felt nearly impossible, and making TotalRating resemble its predecessor has proven to be just as challenging. While promising, this new plugin was never designed for text-only buttons, and shaping it to match my previous setup has been an uphill battle.

TotalRating reactions with 4 emojis
TotalRating before
All right reserved

WordPress hasn’t made things any easier either. Its strict security measures block SVG uploads—a frustrating limitation, even if well-intentioned (see Enabling WordPress to handle SVG files safely). But despite these hurdles, I’m finally approaching the finish line. The emojis are gone, replaced with my carefully crafted text buttons. Still, they don’t look quite right. Compare the two screenshots below: first, my previous reaction buttons, as they once were; second, their current state within TotalRating.

Reaction buttons: Like, Agree, Disagree, Thank you
My previous Reaction buttons
All right reserved
Reaction buttons from TotalRating
Reaction buttons almost ready
All right reserved

Fixing them is the last step in bringing this feature fully back to life—but this time, it won’t be as simple. In fact, when I replaced my original plugin, React & Share – Customizable Reactions Buttons, with the second one, the transition was so seamless that I never even bothered documenting the process in my post about it.

Now, it’s time to make my reaction buttons look and feel as they should.

Exploring TotalRating’s built-in customization features

It provides a range of customization options to refine the look and feel of reaction buttons. It allows users to adjust Emplacement, choosing between placing the reactions before or after the content—I opted for the latter. Beyond that, it provides controls for Colors, Size, Spacing, Roundness, and Tooltip Position, each offering multiple preset choices. These adjustments apply to both Rate (before voting) and Results (how the reactions are displayed after voting). And for those who crave full creative control, the tab includes an option for Custom CSS, which will be the focus of the next section.

TotalRating provides four main color settings: Primary, Secondary, Background, and Dark, each intended to control different aspects of the widget’s appearance 1. To understand their impact, I tested each by setting it to red and using the Preview feature. However, I quickly discovered that the preview didn’t reflect any changes—I had to save each adjustment and check the results live on my site. Through this process, I identified that the Primary color applied to the tooltip (which, I’ll explain later why, it’s not relevant for my setup). The Background setting, unsurprisingly, controlled the widget’s background—though the bright red experiment confirmed that subtlety is key. As for Secondary and Dark, their effects remained elusive, with no visible changes on my site.

After some experimentation—though not with full clarity on all color effects—I decided to replace the default #f2f2f2 background with pure white (#FFFFFF). Whether this was the right call remains to be seen, as subtle differences in background color can influence how elements stand out. For the rest of the color settings, I stuck with the defaults:

  • Primary: #0288D1
  • Secondary: #DDDDDD
  • Dark: #666666

One peculiar behavior worth noting is that TotalRating initially displays reaction images—whether they’re default emojis or custom images—as greyed-out icons until hovered over or clicked. Only then does their true color emerge—in my case, the distinct blueprint-inspired blue I set in my custom-designed SVG buttons. This built-in effect influences how users experience the reactions visually, reinforcing an interactive, engagement-driven design.

As previously mentioned, TotalRating allows fine-tuning several visual aspects, and through the same trial-and-error method I used for colors, I explored the remaining customization options—though the Preview feature remained as unhelpful as ever, forcing me to manually save and check changes live. The available settings include:

Size – Ranging from Small to Large. I opted to scale up from Regular to Large, ensuring better readability and emphasis.

Spacing – Choices include Compact, Normal, and Comfortable. I went with Compact, tightening the layout for a more efficient use of space.

Roundness – A setting that controls button edges, with options for Sharp or Rounded. After testing, I kept it Sharp, as I saw no discernible difference.

Tooltip Position – Either Above or Below the reactions. I moved it to Below, though its text would ultimately be removed later, given that my custom buttons already convey the necessary information.

With these adjustments locked in, the structure of the reaction system is shaping up nicely. The next step? Fine-tuning the design with CSS, where I can fully control the appearance of my text-based buttons.

Taking control with CSS: Will I be up to the task?

One standout feature of TotalRating is its built-in custom CSS field, which offers a convenient way to refine the reaction buttons’ design without modifying the style.css file of my child theme. This ensures a cleaner, more organized approach to customization, keeping all styling adjustments contained within the plugin itself. Not only does this streamline the process, but it also allows for quick experimentation without interfering with broader theme settings.

Box 1: The Inspect Element feature

When tweaking a website’s design, one of the most powerful tools at your disposal is the Inspect Element feature, accessible by right-clicking on any webpage and selecting “Inspect.” This opens your browser’s Developer Tools, offering a behind-the-scenes look at the HTML structure and applied CSS styles—all in real-time.

Beyond simply viewing the applied styles, Inspect Element allows for live modifications, meaning you can adjust font sizes, colors, spacing, and other visual aspects on the fly—without actually altering the underlying code. This makes it an invaluable asset when testing different design approaches before committing changes. And given that TotalRating’s preview functionality has been utterly useless (see above), this tool becomes even more essential in today’s task.

Perhaps the most crucial use of this tool, however, is identifying CSS selectors—the exact class applied to an element. Whether it’s .totalrating-widget, .attibutes, or .description, these identifiers act as unique labels, allowing for precise targeting in your custom CSS. By hovering over an element and reviewing the CSS panel, you can instantly determine the selector needed to modify it. Priceless!

A CSS selector is the first part of a CSS Rule. It is a pattern of elements and other terms that tell the browser which HTML elements should be selected to have the CSS property values inside the rule applied to them. The element or elements which are selected by the selector are referred to as the subject of the selector.Mozilla Developer Network (MDN) Web Docs

In the Inspector Panel, the structure was shown as <p class="description">, making it immediately clear what I needed to target 2. However, when hovering over the element within the inspection tool, the tooltip displayed p.description—a shorthand representation that combines the tag and class for quick reference. This raises an interesting question: should I write my CSS targeting p.description, explicitly referencing the paragraph element? Or would .description alone be sufficient? In practice, it doesn’t really matter—both approaches will work just fine 3. Ultimately, I opted for p.description to add a layer of specificity, ensuring my styles apply exclusively to this paragraph without unintentionally affecting other elements.

p.description {
    font-size: 24px; 
    font-weight: 600; 
    color:#333333;
}

I knew the next step—making my reaction buttons bigger (beyond their stubborn 36 × 9 px)—would be more challenging than the quick CSS tweak I had just pulled off. But I had no idea just how difficult it would actually be. Despite scouring the Inspector Panel and digging through the plugin’s style.css file, there was no trace of the elusive 36-pixel limit restricting my buttons. The images were tucked inside .symbol, yet nowhere did the code explicitly declare: “These buttons shall forever be tiny.” Frustrated but determined, I decided to call for backup. Normally, Copilot is my editor assistant, refining my words rather than unraveling my CSS woes. But this time, I was asking something more ambitious. Could it rise to the challenge? More than I could?

When I explained the problem to Copilot, he came to the same conclusion as me (or so I assume) and suggested that, given the .symbol class contained the reaction images, the logical first step was to try a direct override:

.symbol img {
    width: 48px; /* Adjust as needed */
    height: auto; /* Maintain aspect ratio */
}

This seemed promising—after all, increasing the width should make the buttons larger, and setting height: auto would prevent any unwanted distortion. But when applied? Nothing changed. Copilot had already anticipated this possibility, cautioning that the images might be constrained by an existing max-width or max-height rule elsewhere—one that we hadn’t uncovered yet. So, rather than a quick fix, we were now on a mission to track down the hidden culprit keeping the buttons small.

After further inspection, I discovered that the true culprit might be hidden in .points, the container holding all reaction buttons. This was confirmed when I stumbled upon the rule:

.point > .symbol * {
    max-width: 100%;
    max-height: 100%;
}

At first glance, this seemed harmless—what could be wrong with allowing elements to scale to 100% of their parent’s size? But that’s when Copilot pointed out something critical: if the parent container was already restricted, the images would inherit those limits. In other words, 100% of something tiny is still tiny. So, we attempted to override these limitations with direct !important rules and adjusted .points, but nothing budged. It was clear: this wouldn’t be a simple tweak—it was time to dive deeper into how .points itself was controlling space.

While troubleshooting, Copilot mentioned that Flexbox might be influencing how the images were sized. I hadn’t looked for it yet, but after checking the CSS, there it was—Flexbox rules applied across .attribute, .points, and .point > .symbol. Flexbox is powerful for responsive layouts, but if misconfigured, it can accidentally shrink elements due to flex-grow, flex-shrink, or align-items. Copilot immediately spotted that .point > .symbol was explicitly setting width and height using 1em and font-size: 1.5em—which meant the images inside .symbol were shrinking instead of adjusting freely. To break free of these constraints, Copilot suggested shifting from em-based sizing to explicit pixel values, ensuring the buttons had enough room to display correctly:

.point > .symbol {
    width: 48px !important; /* Override small em-based sizing */
    height: 48px !important;
    font-size: unset; /* Remove restrictive font-based scaling */
}

.point > .symbol img {
    width: 100% !important; /* Ensure image fills container */
    height: auto !important;
}

But the victory was only partial. While they now appeared larger, the size was still too small on my laptop, and worse—they weren’t adapting dynamically across different screen sizes. Clearly, another challenge awaited: making the buttons responsive without forcing a fixed size.

Copilot suggested moving away from em-based sizing, which had been restricting the buttons, and instead embracing relative units like vw (viewport width). This would allow the buttons to scale naturally, adjusting based on the screen dimensions rather than staying fixed. The first suggestion was to set each button’s width to 4vw—but after testing, I quickly realized that was too small, especially on my laptop. Increasing it to 8vw made things more readable, but I eventually settled on 7vw, which struck the right balance between visibility and spacing.

.point > .symbol {
    width: 7vw; /* Adjust dynamically based on screen width */
    height: auto; /* Maintain aspect ratio */
}

.point > .symbol img {
    width: 100%; /* Ensure image fully fills its parent */
    height: auto;
}

While 7vw seemed perfect, there was one unexpected issue—on hover, the buttons increased in size, throwing off the layout and causing them to touch each other. I investigated and found that a transform: scale(1.35); rule was silently inflating the button size when hovered or checked. To remove this effect, Copilot suggested an override:

.can-rate.is-count .points .point.is-checked .symbol,
.can-rate.is-count .points:hover .point:hover:not(.is-checked) .symbol {
    transform: none !important;
}

With the hover effect removed and the reaction buttons scaling properly, one last hurdle remained—ensuring they adapted seamlessly to different screens without overflowing or becoming too small on mobile. Copilot suggested media queries to dynamically adjust the size based on screen width:

.point > .symbol {
    width: 7vw; /* Default size for larger screens */
    height: auto;
}

/* Adjust for smaller screens */
@media (max-width: 600px) {
    .point > .symbol {
        width: 8vw; /* Increase size for mobile */
    }
}

But just when I thought we had everything figured out, closing the dev tools on my laptop revealed another bug: the buttons expanded beyond the plugin background 4, spilling into the sidebars! I wasn’t sure how to fix this, but then I had a realization:

Rather than manually adjusting the size, is there a way to let the plugin itself determine how big the buttons should be within the background? That way, they could expand naturally without overflowing.CogitActive

While I had the concept, I still followed Copilot’s lead to turn it into a functional solution. We tried different overrides—forcing .symbol img to take up 100% of its container, removing restrictive max-height constraints, and adjusting .points to handle responsiveness. None of it worked. The images remained stuck at 9px high, refusing to scale up despite every CSS tweak.

The real breakthrough came when Copilot pointed out that the parent container itself needed explicit size settings. We needed .symbol to fully embrace the available space within .point, rather than being passively constrained by inherited rules.

.point > .symbol {
    display: flex;
    justify-content: center;
    align-items: center;
    width: 100%; /* Make it take the full available space */
    height: 100%; /* Match the parent size */
    max-width: none !important;
    max-height: none !important;
}

.point > .symbol img {
    width: 100% !important; /* Ensure full scaling */
    height: auto !important; /* Maintain aspect ratio */
    object-fit: contain; /* Ensure it fits properly within parent */
}

.can-rate.is-count .points .point.is-checked .symbol,
.can-rate.is-count .points:hover .point:hover:not(.is-checked) .symbol {
    transform: none !important;
}

With this, the buttons finally expanded correctly within the plugin background—adjusting naturally to available space without breaking the layout. After countless tweaks and troubleshooting, the reaction buttons were finally perfect—visually balanced, fully scalable, and seamlessly responsive.

TotalRating Reaction buttons
Reaction buttons finally as envisioned
All right reserved

Final thoughts

What started as a simple goal turned into a full-scale debugging adventure. Without Copilot, I would never have unraveled the hidden CSS constraints, Flexbox quirks, and scaling mysteries lurking beneath the surface. Through countless tweaks, trial and error, and breakthrough moments, I finally got the reaction system exactly as I envisioned it. And while I may have had a few insights along the way, Copilot was the guiding force behind every technical solution, leading me step by step until it all came together.

Honestly? I wouldn’t have managed this without it.

Now that the reaction buttons are fully revamped, I’d love for you to put them to the test! Whether you found this post informative, interesting, or even not worth it (hey, honesty is welcome!), let me know with just a click. These reactions aren’t just for fun—they help shape the content I create and improve future posts.

So go ahead, rate this post, and let me know what you think!


1 See How to customize appearance (external link). ^
2 Quick reminder: the Title field automatically renders as an <h4>, which isn’t ideal for maintaining semantic hierarchy. That’s why I opted for the Description field instead—ensuring proper structure while keeping accessibility in check. ^
3 While both selectors function correctly, p.description ensures the styling applies exclusively to <p> elements with this class, whereas .description could target other elements as well. Choosing between them depends on whether broader flexibility or precise targeting is preferred. ^
4 I had just put the background back—still hesitating between my preferred white or the plugin’s default color—but this issue made me reconsider everything again. Surprisingly, having the buttons extend into the sidebars gave off a Gutenberg full-block experience, setting my reaction system apart from the rest. This unintended effect made me question whether a different background color could enhance this unique layout rather than restrict it. ^