Building a Reaction Component

We’re all familiar with dev.to’s “Reaction Component” (although I’m still not sure, what the unicorn is for!) Here’s a short tutorial on how to create a “Reaction Component” – both with and without JavaScipt.

Let’s start with the CSS version!


This content originally appeared on DEV Community and was authored by Mads Stoumann

We're all familiar with dev.to's “Reaction Component” (although I'm still not sure, what the unicorn is for!) Here's a short tutorial on how to create a “Reaction Component” – both with and without JavaScipt.

Let's start with the CSS version!

Markup

We're going to wrap each reaction in a <label>, and add the <svg> and an empty <span> after a <input type="checkbox">:

<label aria-label="React with heart">
  <input type="checkbox" name="reaction-heart" value="75" style="--c:75" />
  <svg></svg>
  <span></span>
</label>

The <input type="checkbox"> is what we'll use to control both state and value.

Icon

On dev.to, two different icons are used, when you “react” to something. For the “like“-action, there's an unfilled heart and a filled heart. Same story for the “unicorn” and “bookmark”-reactions.

One could argue, that with slight design changes, the icons could simply toggle SVG's fill, stroke or stroke-width – but let's leave it at two icons. We'll <g>roup them within a single SVG:

<svg viewBox="0 0 24 24">
  <g><path d="M21.179 12.794l.013.014L12 22l-9.192-9.192.013-.014A6.5 6.5 0 0112 3.64a6.5 6.5 0 019.179 9.154zM4.575 5.383a4.5 4.5 0 000 6.364L12 19.172l7.425-7.425a4.5 4.5 0 10-6.364-6.364L8.818 9.626 7.404 8.21l3.162-3.162a4.5 4.5 0 00-5.99.334l-.001.001z"></path></g>
  <g><path d="M2.821 12.794a6.5 6.5 0 017.413-10.24h-.002L5.99 6.798l1.414 1.414 4.242-4.242a6.5 6.5 0 019.193 9.192L12 22l-9.192-9.192.013-.014z"></path></g>
</svg>

In CSS, we an use the :checked pseudo-selector to toggle between the two icons (in <g>-tags):

[name*="reaction-"]:checked + svg g:first-of-type,
[name*="reaction-"]:not(:checked) + svg g:last-of-type {
  opacity: 0;
}
[name*="reaction-"]:checked + svg g:last-of-type {
  opacity: 1;
}

Cool, now we can toggle between the two icons using the checkbox, let's add a counter! Did you notice the style="--c:75" in the markup?

We'll use that for a CSS counter:

counter-reset: reaction var(--c);

Unfortunately, we can't use the value-attribute, as in:

counter-reset: reaction attr(value);

– so we have to use that extra custom property, --c, for the initial value.

Then, we'll hook into the :checked-selector again:

[name*="reaction-"]:checked {
  counter-increment: reaction;
}

And that empty <span> in the markup will now play it's part:

span::after {
  content: counter(reaction);
}

But why the empty <span>? That's because we have to add the counter as pseudo-element content (::before or ::after).

Unfortunately, we can't add a pseudo-element to the <input type="checkbox">, as <input>-tags are part of the group of tags, that can't have children (aka “self-closing” tags) or pseudo-content (actually they can in Chrome and Safari, but it's not part of the spec!).

The rest is just bits of styling. Here's the CSS-only example on Codepen:

JavaScript

Even though the CSS-only version is cool, it's not very practical. You'll probably want to store the reaction somewhere!

Let's remove the counter-related stuff from the CSS, and the style="--c"-part from the markup. We'll wrap the reactions in a <form id="react">, and listen for changes using the onchange-eventListener:

react.addEventListener('change', (e) => {
  const t = e.target;
  t.parentNode.lastElementChild.innerText = t.value = t.value - 0 + (t.checked ? 1 : -1);
});

This small snippet will add or subtract 1(one) from the value of the current reaction, then set the innerText of the <span> to that.

It's within this snippet, you can add a fetch() (with POST) to store the current reaction.

On dev.to, for instance, a small JSON-object is POSTed:

{
  result: "create",
  category: "like"
}

Example, using JavaScript:

If you want to set the text of all the <span>-elements to the value of the <input>s, use this small snippet to iterate the elements-collection of the <form>:

[...react.elements].forEach(t => t.parentNode.lastElementChild.innerText = t.value);

That's it! Recently, there was a “Star Rating”-challenge here on dev.to (my entries were Star Rating Using a Single Input and Mood Selector).

It's always interesting to see how other developers solve problems, so please share a link in the comments, if you modify my example, or – event better – make your own “Reaction Component”!


This content originally appeared on DEV Community and was authored by Mads Stoumann


Print Share Comment Cite Upload Translate Updates
APA

Mads Stoumann | Sciencx (2021-07-17T08:24:00+00:00) Building a Reaction Component. Retrieved from https://www.scien.cx/2021/07/17/building-a-reaction-component/

MLA
" » Building a Reaction Component." Mads Stoumann | Sciencx - Saturday July 17, 2021, https://www.scien.cx/2021/07/17/building-a-reaction-component/
HARVARD
Mads Stoumann | Sciencx Saturday July 17, 2021 » Building a Reaction Component., viewed ,<https://www.scien.cx/2021/07/17/building-a-reaction-component/>
VANCOUVER
Mads Stoumann | Sciencx - » Building a Reaction Component. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2021/07/17/building-a-reaction-component/
CHICAGO
" » Building a Reaction Component." Mads Stoumann | Sciencx - Accessed . https://www.scien.cx/2021/07/17/building-a-reaction-component/
IEEE
" » Building a Reaction Component." Mads Stoumann | Sciencx [Online]. Available: https://www.scien.cx/2021/07/17/building-a-reaction-component/. [Accessed: ]
rf:citation
» Building a Reaction Component | Mads Stoumann | Sciencx | https://www.scien.cx/2021/07/17/building-a-reaction-component/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.