Reputation: 115
I have the following code which I found on codepen and works and looks great!
.switch-field {
display: flex;
margin-bottom: 36px;
overflow: hidden;
}
.switch-field input {
position: absolute !important;
clip: rect(0, 0, 0, 0);
height: 1px;
width: 1px;
border: 0;
overflow: hidden;
}
.switch-field label {
background-color: #e4e4e4;
color: rgba(0, 0, 0, 0.6);
font-size: 14px;
line-height: 1;
text-align: center;
padding: 8px 16px;
margin-right: -1px;
border: 1px solid rgba(0, 0, 0, 0.2);
box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.3), 0 1px rgba(255, 255, 255, 0.1);
transition: all 0.1s ease-in-out;
}
.switch-field label:hover {
cursor: pointer;
}
.switch-field input:checked + label {
background-color: #a5dc86;
box-shadow: none;
}
.switch-field label:first-of-type {
border-radius: 4px 0 0 4px;
}
.switch-field label:last-of-type {
border-radius: 0 4px 4px 0;
}
<form class="form">
<div class="switch-field">
<input type="radio" id="radio-three" name="switch-two" value="yes" checked/>
<label for="radio-three">One</label>
<input type="radio" id="radio-four" name="switch-two" value="maybe" />
<label for="radio-four">Two</label>
<input type="radio" id="radio-five" name="switch-two" value="no" />
<label for="radio-five">Three</label>
</div>
</form>
But unfortunately my generated HTML is laid out as follows (with the input inside the label):
<form class="form">
<div class="switch-field">
<label for="radio-three">
<input type="radio" id="radio-three" name="switch-two" value="yes" checked/>
One</label>
<label for="radio-four">
<input type="radio" id="radio-four" name="switch-two" value="maybe" />
Two</label>
<label for="radio-five">
<input type="radio" id="radio-five" name="switch-two" value="no" />
Three</label>
</div>
</form>
I am wondering if its possible just with CSS to adapt this class to make it work or if JS is necessary.
.switch-field input:checked + label {
background-color: #a5dc86;
box-shadow: none;
}
Many thanks in advance!
Upvotes: 1
Views: 3079
Reputation: 485
You should use JS.
When input element is inside the label then we do not need id on the element and 'for' attribute on the label, but when it is outside we need it.
<label>
Foo
<input name="foo" type="checkbox" />
</label>
Based on your HTML Code, To alter the styling of the label, would require a selector that affected the parent, which currently isn't possible. Why? https://css-tricks.com/parent-selectors-in-css/
<input id="foo" name="foo" type="checkbox" />
<label for="foo">Foo</label>
So, to select the label of the :checked input, we need the label to be adjacent, not the parent.
But in your code, HTML's label and input is implicit connecting. So I think the solution is to use JS.
let form = document.querySelector("form");
form.addEventListener("change", (event) => {
let target = event.target;
let targetParent = target.parentElement;
if (
target.type === "radio" &&
targetParent &&
targetParent.tagName.toLowerCase() === "label"
) {
let prior = form.querySelector('label.checked input[name="' + target.name + '"]');
if (prior) {
prior.parentElement.classList.remove("checked");
}
targetParent.classList.add("checked");
}
}, false);
.switch-field {
display: flex;
margin-bottom: 36px;
overflow: hidden;
}
.switch-field input {
position: absolute !important;
clip: rect(0, 0, 0, 0);
height: 1px;
width: 1px;
border: 0;
overflow: hidden;
}
.switch-field label {
background-color: #e4e4e4;
color: rgba(0, 0, 0, 0.6);
font-size: 14px;
line-height: 1;
text-align: center;
padding: 8px 16px;
margin-right: -1px;
border: 1px solid rgba(0, 0, 0, 0.2);
box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.3), 0 1px rgba(255, 255, 255, 0.1);
transition: all 0.1s ease-in-out;
}
.switch-field label:hover {
cursor: pointer;
}
.switch-field label.checked {
background-color: #a5dc86;
box-shadow: none;
}
.switch-field label:first-of-type {
border-radius: 4px 0 0 4px;
}
.switch-field label:last-of-type {
border-radius: 0 4px 4px 0;
}
<form class="form">
<div class="switch-field">
<label class="checked">
<input type="radio" name="switch-two" value="yes" checked />
One
</label>
<label>
<input type="radio" name="switch-two" value="maybe" />
Two
</label>
<label>
<input type="radio" name="switch-two" value="no" />
Three
</label>
</div>
</form>
Upvotes: 1
Reputation: 43880
The pseudo-selector :focus-within
. Should an element have any children element that has focus, that parent will have styles applied to it. So a radio button that the user checks will trigger a focus event and in doing so activate the CSS ruleset that has :focus-within
which is the label in the following example.
.switch-field label:focus-within {
background-color: #a5dc86;
box-shadow: none;
}
<form class="form">
<div class="switch-field">
<label for="radio-three">
<input type="radio" id="radio-three" name="switch-two" value="yes" checked/>
One</label>
<label for="radio-four">
<input type="radio" id="radio-four" name="switch-two" value="maybe" />
Two</label>
<label for="radio-five">
<input type="radio" id="radio-five" name="switch-two" value="no" />
Three</label>
</div>
</form>
Upvotes: 2
Reputation: 812
Here is example of how you can achieve desired functionality through javascript
var checkboxes = document.querySelectorAll("input[type=radio]");
var labels = document.querySelectorAll("label");
labels[0].classList.add("checkedLabel");
checkboxes.forEach(function(checkbox) {
checkbox.addEventListener('change', function(e) {
Array.from(labels).forEach(function(el) {
el.classList.remove('checkedLabel');
});
this.parentElement.classList.add("checkedLabel");
})
})
.checkedLabel {
background-color: #a5dc86;
box-shadow: none;
}
<form class="form">
<div class="switch-field">
<label for="radio-three">
<input type="radio" id="radio-three" name="switch-two" value="yes" checked/>
One</label>
<label for="radio-four">
<input type="radio" id="radio-four" name="switch-two" value="maybe" />
Two</label>
<label for="radio-five">
<input type="radio" id="radio-five" name="switch-two" value="no" />
Three</label>
</div>
</form>
Upvotes: 1
Reputation: 1093
Yes, replace .switch-field input
with .switch-field label input
.
A selector of the form x1 x2 x3 ... xn—1 xn
(space separated) means xn
which is a descendent of xn−1
and so on.
Upvotes: 0