From 14d227d46a2177a8928333894252d6299f531097 Mon Sep 17 00:00:00 2001 From: Bradley Taunt Date: Mon, 27 Nov 2023 12:25:51 -0500 Subject: Trying to render posts all at once --- posts/dynamic-checkboxes.md | 411 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 411 insertions(+) create mode 100644 posts/dynamic-checkboxes.md (limited to 'posts/dynamic-checkboxes.md') diff --git a/posts/dynamic-checkboxes.md b/posts/dynamic-checkboxes.md new file mode 100644 index 0000000..d1b63c6 --- /dev/null +++ b/posts/dynamic-checkboxes.md @@ -0,0 +1,411 @@ +# Dynamic Checkboxes + +2019-07-30 + +Checkboxes are used quite frequently on forms across the web. Whether you're selecting a pricing plan during a site's sign-up process or just simply selecting to opt-out from a newsletter, you have most likely interacted with some form of checkbox element. + +What if we could make everyday checkboxes more beautiful *and* more intuitive? *It's easier than you think*. We only need a small amount of CSS and JavaScript to make considerable improvements to your average checkbox UX. + +Let's get into it. + +## What we are building +Take a look and play around with the CodePen below to get an idea of what we are going to build. The premise is a simple add-on pricing form which calculates the additional monthly total to the user in real-time. + +[Live CodePen Example](https://codepen.io/bradleytaunt/pen/rXWEpy/) + +## The Structure (HTML) + +As always, we will start by breaking down the "bones" of the HTML structure for this checkbox form. Let's take a look at the HTML in it's entirety (don't worry, it is a lot more simple than it seems at first glance): + + +

Add-ons

+ + + + + + + + + + +
+

Your Plan

+
+ $ + 0 + + /mo +
+
+ + +### The checkbox inputs & labels + + + + + + + + + +1. This input will be hidden via `position:absolute` by default. All checkbox inputs need to share the same `name` value and all checkboxes require their our custom `id` that will link with the corresponding `for` value on the label. + +2. This label needs it's `for` value to correspond with it's partnered checkbox. + - i) The first span holds the title and description information of the add-on + - ii) The last span holds the cost associated with the current add-on + +### The total cost container output + + + +
+ +

Your Plan

+ + +
+ + + $ + + + 0 + + + + + + /mo + +
+ +
+ + +1. A simple `div` with a class we can easily target later + +2. A `div` parent container is needed to house all the total `spans` together (more on this when we get into the CSS) + - i) The first `span` holds the static currency symbol + - ii) The second `span` is where our updated cost will be injected + - iii) This input field is required for us to take-in the `value` of the associated `:checked` inputs and add them together. This current value is then used for the injection into the second `span` + - iv) The final `span` simply holds the static monthly duration content + +All that's all we need for the HTML! + +## The Visuals (CSS) + +Again, lets take a look at the entire file before we break it down step-by-step: + + + .checkbox-label { + align-items: center; + background-color: none; + border: 1px solid lightgrey; + border-radius: 5px; + cursor: pointer; + display: flex; + font-weight: 600; + justify-content: space-between; + margin: 0 auto 10px; + padding: 20px 20px 20px 70px; + position: relative; + transition: .3s ease all; + width: 100%; + } + .checkbox-label span:last-child { + padding: 0 0 0 20px; + } + .checkbox-label:hover { + background-color: rgba(255,255,255,0.2); + } + .checkbox-label:before { + background-repeat: no-repeat; + background-position: center; + background-size: 15px; + border: 1px solid lightgrey; + border-radius: 50%; + content:''; + height: 30px; + left: 20px; + position: absolute; + top: calc(50% - 15px); + transition: .3s ease background-color; + width: 30px; + } + .checkbox-label:hover:before { + background-image: + url('data:image/svg+xml;utf8,'); + } + .checkbox-label span { + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; + } + .checkbox-label span em { + display: block; + font-size: 80%; + font-style: normal; + font-weight: 400; + line-height: 1.2; + } + .checkbox-btn { + position: absolute; + visibility: hidden; + } + .checkbox-btn:checked + .checkbox-label { + background-color: white; + border-color: mediumpurple; + box-shadow: 0 2px 4px rgba(0,0,0,0.05); + } + .checkbox-btn:checked + .checkbox-label:before { + background-color: mediumpurple; + background-image: + url('data:image/svg+xml;utf8,'); + border-color: mediumpurple; + } + + .total-cost { + align-items: baseline; + border-top: 1px solid lightgrey; + display: flex; + justify-content: space-between; + margin-top: 40px; + padding: 40px 20px 0; + } + .total-cost div { + align-items: baseline; + display: flex; + } + .total-cost span:nth-child(1) { + align-self: flex-start; + padding-top: 5px; + } + .total-cost span:nth-child(2) { + font-size: 32px; + font-weight: bold; + } + .total-cost input { + display: none; + } + + @media(max-width:480px) { + .checkbox-label { + align-items: flex-start; + flex-direction: column; + flex-wrap: wrap; + } + .checkbox-label span:last-child { + padding: 10px 0 0 0; + } + } + + +### The checkbox label + + + /* + This is the main element for each checkbox "container". + Inside it houses the title, description and price. + */ + .checkbox-label { + align-items: center; + background-color: none; + border: 1px solid lightgrey; + border-radius: 5px; + cursor: pointer; + display: flex; + font-weight: 600; + justify-content: space-between; + margin: 0 auto 10px; + padding: 20px 20px 20px 70px; + position: relative; + transition: .3s ease all; + width: 100%; + } + .checkbox-label:hover { + background-color: rgba(255,255,255,0.2); + } + + /* Update the label styling when the input is :checked */ + .checkbox-btn:checked + .checkbox-label { + background-color: white; + border-color: mediumpurple; + box-shadow: 0 2px 4px rgba(0,0,0,0.05); + } + + +### The custom checkbox input + +We need to hide the browser's default checkbox input and replace it with our own using pseudo selectors. + + + /* Hide browser default input */ + .checkbox-btn { + position: absolute; + visibility: hidden; + } + + /* Our custom input checkbox */ + .checkbox-label:before { + background-repeat: no-repeat; + background-position: center; + background-size: 15px; + border: 1px solid lightgrey; + border-radius: 50%; + content:''; + height: 30px; + left: 20px; + position: absolute; + top: calc(50% - 15px); + transition: .3s ease background-color; + width: 30px; + } + + /* + Here we add a simple '+' icon on hover + to our custom pseudo element. + Adding it as an inline SVG gives us the + ability to fully customize it's styling + */ + .checkbox-label:hover:before { + background-image: + url('data:image/svg+xml;utf8,'); + } + + /* + When the checkbox input is :checked we need to + update the inline SVG to use a checkmark symbol + */ + .checkbox-btn:checked + .checkbox-label:before { + background-color: mediumpurple; + background-image: + url('data:image/svg+xml;utf8,'); + border-color: mediumpurple; + } + + +### The total cost container + +We only need some very basic flexbox styling for our bottom "total" container: + + + .total-cost { + align-items: baseline; + border-top: 1px solid lightgrey; + display: flex; + justify-content: space-between; + margin-top: 40px; + padding: 40px 20px 0; + } + .total-cost div { + align-items: baseline; + display: flex; + } + .total-cost span:nth-child(1) { + align-self: flex-start; + padding-top: 5px; + } + .total-cost span:nth-child(2) { + font-size: 32px; + font-weight: bold; + } + + /* + This input is used in our JavaScript - look at the + function part of this post to understand why + */ + .total-cost input { + display: none; + } + + +### Last but not least - mobile + +Now we just ensure that on smaller devices our checkbox labels render nicely: + + + @media(max-width:480px) { + /* + Avoids the inner label content from squishing together + and becoming unreadable + */ + .checkbox-label { + align-items: flex-start; + flex-direction: column; + flex-wrap: wrap; + } + .checkbox-label span:last-child { + padding: 10px 0 0 0; + } + } + + +That's it for the styling! + +## The Function (JS) + +As you can see below, we only need a very minor amount of JavaScript to accomplish our total cost "injection". + + + window.onload=function(){ + + // Place the default browser checkbox inputs into a variable + var inputs = document.getElementsByClassName('checkbox-btn') + + // Now we loop through the inputs and check if they are + // greater than zero. If so, we run our function. + for (var i=0; i < inputs.length; i++) { + + inputs[i].onchange = function() { + + // Create `add` variable which takes the :checked input value + var add = this.value * (this.checked ? 1 : -1); + + // We grab the current total value on our hidden input field and return it + // as a floating point number + // (since in this use case it will be a price number based on currency) + var new_total = parseFloat(document.getElementById('output').value); + + // Now we simply add the existing total value with the newly ":checked" input value + var updated_total = document.getElementById('output').value=new_total + add + + // Place the new updated total directly inside the `total-cost-inner` span element + document.getElementById('total-cost-inner').innerHTML = updated_total; + } + + } + } + + +That's it! Feel free to play with the demo some more at the top of the post, or check out the [CodePen source directly](https://codepen.io/bradleytaunt/pen/rXWEpy). -- cgit v1.2.3-54-g00ecf