Using custom wrappers for inputs: pros and cons? - javascript

Often there are times when I need to have totally custom input elements: checkboxes, radio buttons, selects, etc.
Just wanted to ask if such practice is okay and acceptable:
we create some sort of wrapper for our input (radio box in this case)
we hide our real radio boxes(opacity: 0, visibility: hidden, left: -9999px, etc)
On click on a parent wrapper: we get the input name attribute, find all inputs with [type="radio][name="clickedInputName"], set them all to become unchecked and set the one we clicked to set it to checked.
Attaching some not quite beautiful jsfiddle: https://jsfiddle.net/moLvh9dd/
$('.radio-wrapper').on('click', function(e){
e.preventDefault();
var targetInput = $(this).find($('input'));
var clickedInputName = 'input[type="radio"] [name="'+targetInput.attr('name')+'"]';
$(clickedInputName).each(function(){
$(this).prop('checked', false);
$(this).parent().removeClass('input-checked');
})
targetInput.prop('checked', true);
$(this).addClass('input-checked');
});
Checked the browser compatibility, + - works everywhere down to IE8, so despite the fact that it just works I want to know if it's the right way? Is it acceptable?`
Despite the fact that it's javascript/jQuery dependent.
EDIT:
Thanks for some great answers on radio and checkbox inputs but what about custom select element? With various amount of options for every select?
For example like here - some ugly jQuery again: https://jsfiddle.net/4gt7gavq/

You can follow an alternative without using JS with pure CSS or using images.
In here you can find both techniques explained, i would advise the pure CSS way of course but that depends on your cross-browser requirements.
Pure CSS styling
The demonstration below is styled purely using CSS. Unlike the image-based method, the pure CSS method scales with the text size.
The HTML used for each checkbox or radio button is similar to that in the image-based method:
<div>
<input id="option" type="checkbox" name="field" value="option">
<label for="option"><span><span></span></span>Value</label>
</div>
The span elements inside the label are used to create the alternative graphics. While radio buttons require both spans, only one is needed for checkboxes.
We hide the checkboxes and radio buttons in the stylesheet:
input[type=checkbox]:not(old),
input[type=radio ]:not(old){
width : 2em;
margin : 0;
padding : 0;
font-size : 1em;
opacity : 0;
}
The technique is the same as in the image-based method, but because the width is set relative to the font size in line 3 we must restore the font size in line 6, as browsers use a smaller font size for checkboxes and radio buttons by default.
We then position the label:
input[type=checkbox]:not(old) + label,
input[type=radio ]:not(old) + label{
display : inline-block;
margin-left : -2em;
line-height : 1.5em;
}
Again, the technique is the same as in the image-based method, but using relative units. The padding is not required as the scalable graphics, unlike a background image, will push the label text along.
We then style the first span to create the unchecked graphics:
input[type=checkbox]:not(old) + label > span,
input[type=radio ]:not(old) + label > span{
display : inline-block;
width : 0.875em;
height : 0.875em;
margin : 0.25em 0.5em 0.25em 0.25em;
border : 0.0625em solid rgb(192,192,192);
border-radius : 0.25em;
background : rgb(224,224,224);
background-image : -moz-linear-gradient(rgb(240,240,240),rgb(224,224,224));
background-image : -ms-linear-gradient(rgb(240,240,240),rgb(224,224,224));
background-image : -o-linear-gradient(rgb(240,240,240),rgb(224,224,224));
background-image : -webkit-linear-gradient(rgb(240,240,240),rgb(224,224,224));
background-image : linear-gradient(rgb(240,240,240),rgb(224,224,224));
vertical-align : bottom;
}
The techniques used here are described in detail in the page on styling buttons with CSS3. Line 15 ensures the graphics are positioned at the bottom of the label rather than the baseline of the text.
In the example, the background gradient is reversed on selected checkboxes and radio buttons:
input[type=checkbox]:not(old):checked + label > span,
input[type=radio ]:not(old):checked + label > span{
background-image : -moz-linear-gradient(rgb(224,224,224),rgb(240,240,240));
background-image : -ms-linear-gradient(rgb(224,224,224),rgb(240,240,240));
background-image : -o-linear-gradient(rgb(224,224,224),rgb(240,240,240));
background-image : -webkit-linear-gradient(rgb(224,224,224),rgb(240,240,240));
background-image : linear-gradient(rgb(224,224,224),rgb(240,240,240));
}
We then display a tick inside selected checkboxes:
input[type=checkbox]:not(old):checked + label > span:before{
content : '✓';
display : block;
width : 1em;
color : rgb(153,204,102);
font-size : 0.875em;
line-height : 1em;
text-align : center;
text-shadow : 0 0 0.0714em rgb(115,153,77);
font-weight : bold;
}
The selector in line 1 uses the :before pseudo-class so that line 2 can insert a tick symbol inside the span element. Lines 3, 4, 6, 7, and 8 display the tick centrally within the element, while lines 5, 9, and 10 style the text.
Finally, we display a ‘bullet’ inside selected radio buttons, applying the same techniques as for the unchecked graphics to the second span element:
input[type=radio]:not(old):checked + label > span > span{
display : block;
width : 0.5em;
height : 0.5em;
margin : 0.125em;
border : 0.0625em solid rgb(115,153,77);
border-radius : 0.125em;
background : rgb(153,204,102);
background-image : -moz-linear-gradient(rgb(179,217,140),rgb(153,204,102));
background-image : -ms-linear-gradient(rgb(179,217,140),rgb(153,204,102));
background-image : -o-linear-gradient(rgb(179,217,140),rgb(153,204,102));
background-image : -webkit-linear-gradient(rgb(179,217,140),rgb(153,204,102));
background-image : linear-gradient(rgb(179,217,140),rgb(153,204,102));
}
http://code.stephenmorley.org/html-and-css/styling-checkboxes-and-radio-buttons/#pureCSS
Select element
On the select element you can change colors, borders and the drop-down arrow. Not much more.
To do this create a png with the custom arrow and set it as element brackground:
.styled-select {
width: 240px;
height: 34px;
overflow: hidden;
background: url(new_arrow.png) no-repeat right #ddd;
border: 1px solid #ccc;
}
http://bavotasan.com/2011/style-select-box-using-only-css/

These practices are very much acceptable. For the most part, as long as the form is still accessible and usable with JavaScript and/or CSS disabled, you're OK.
To expand on one of my comments above with some sample code for the example provided in the original question, you can achieve this through CSS alone, without any need for JavaScript.
What you need to do is use labels with pseudo elements and then use the :checked pseudo class with an adjacent selector to change the styles of those pseudo elements.
More information on adjacent selectors
More information on the :checked pseudo class
This has the added benefit of requiring less markup, as well, but that will depend on your overall layout.
Here's the sample code:
*,*:before,*:after{box-sizing:border-box;font-family:sans-serif;}
input.radio{
left:-9999px;
position:absolute;
}
label.radio{
cursor:pointer;
display:block;
line-height:20px;
margin:0 0 10px;
padding:0 0 0 26px;
position:relative;
}
label.radio:before{
border:1px solid #f00;
border-radius:50%;
content:"";
display:block;
height:16px;
left:5px;
position:absolute;
top:2px;
width:16px;
}
label.radio:after{
background:#f00;
border-radius:50%;
content:"";
display:block;
height:8px;
left:9px;
opacity:0;
position:absolute;
top:6px;
transform:scale(0);
transition:transform .25s,opacity .5s;
width:8px;
}
input.radio:checked+label.radio:after{
opacity:1;
transform:scale(1);
}
<input class="radio" name="radio-option" id="option1" type="radio" value="1">
<label class="radio" for="option1">Option 1</label>
<input class="radio" name="radio-option" id="option2" type="radio" value="2">
<label class="radio" for="option2">Option 2</label>
<input class="radio" name="radio-option" id="option3" type="radio" value="3">
<label class="radio" for="option3">Option 3</label>
<input class="radio" name="radio-option" id="option4" type="radio" value="4">
<label class="radio" for="option4">Option 4</label>

As a drawback of replacing the original input element, you will lose the ability to focus and change the value of this element with the keyboard (tabindex).

Related

Need Recommendation on css for implementing Toggle Switch Button

My requirement was to show a toggle button with a message on it's right for mobile website. I have implemented this but I am not sure how good it is & if it will work on most of the mobile browsers. I am very new to the UI development & this is the first time I have implemented a UI component. To give an idea, this final implemented result look somewhat similar to this
I have broken down this requirement into 5 parts -
1. The container - Parent div
2. Checkbox. - Hidden checkbox behind button
3. The button
4. The inner circle of button
5. The message string which will be shown on the right.
Additionally, this button needs to be disabled for first few seconds of page. By disabling, I mean it should be unclickable & it's UX would be little different so that user knows that it's disabled.
HTML -
<div class = "toggleSwitchContainer">
<div class = "my-toggle-button" disabled = "true">
<input type="checkbox" id = "checkBox">
<div class = "toggle-switch-inner-circle" disabled = "true"> </div>
</div>
<div class = "messageString" disabled = "true">
<text>Some message</text>
</div>
</div>
CSS -
.toggleSwitchContainer {
padding : 10px;
}
.my-toggle-button[disabled] {
width : 40px;
height : 20px;
background-color : #dddddd47;
border-radius : 30px;
border-color : #80808017;
}
.my-toggle-button {
width : 44px;
height : 22px;
background-color : #eff0f3;
border-radius : 30px;
position : relative;
transition : all 300ms ease-in-out;
display : inline-block;
border : solid 1px;
border-color : #80808080;
}
.my-toggle-button.active {
background-color : #ff7800;
}
.my-toggle-button > .toggle-switch-inner-circle {
position : absolute;
width : 20px;
height : 20px;
background-color : #eff0f3;
border-radius : 50%;
border : solid 1px;
border-color : #80808080;
transition : all 300ms ease-in-out;
top : 0;
}
.my-toggle-button.active > .toggle-switch-inner-circle {
margin-left : 22px;
background-color : #fff;
}
.messageString[disabled] {
color : #00000024;
}
.messageString {
display : inline-block;
padding : 10px;
}
.my-toggle-button input {
opacity: 0;
width: 0;
height: 0;
}
JS
Function to handle click -
toggleSwitchObject.unbind().click(function() {
toggleSwitchObject[0].classList.toggle('active');//On click inner circle will be moved to right & background color will change.
callRequiredFunctionNow();
});
Disable -
containerDomNode.children().attr('disabled', true);
So, the idea is to append a css property called 'active' on click of the switch so that the inner circle is moved to right & background color is changed. I need to know if there is any risky css property I am using which may not work on many browsers. Specifically, the transition property looks scary to me. Is there any scope of improvement in this implementation?

CSS / HTML double font color into a SELECT OPTION

I have a little problem with customize CSS/HTML of select option
This is my code :
<select id="Month" class="form-styling-date splash_small required" title=" " style="" name="Month" tabindex="12">
<option value="1">Janvier</option>
<option value="2">Février</option>
....
<option value="11">Novembre</option>
<option value="12">Décembre</option>
<option value="9999" selected="selected">Mois</option>
</select>
This is my CSS code :
.form-styling-date {
width: 100px;
height: 35px;
padding-left: 15px;
border: none;
border-radius: 20px;
margin-bottom: 20px;
color:#FFF;
background: rgba(255,255,255,.2);
}
you can see the problem in : https://gayurban.com/sync/indexv2.php and select SIGN UP option into BIRTHDAY
I customise CSS to write the selected option in WHITE when is selected, so when you select the arrow to see all the options, the background AND font color set to white. So i can't see the list of options.
How can change this font color to BLACK and when is selected turn to WHITE because when i set the font color to BLACK i see the list so font color black into the form is not really a visible choice.
Thank for your help
color property on select will set color of option(s) text (including selected), while adding / over-riding color to select option will set color of options excluding selected option, which will be set based on the value specified for select.
CSS:
select {
color: white; /* color of selected option */
}
select option {
color: black; /* color of other options */
}
Also, better to add generic styles to tag selector, if you want your component CSS to remain same through your site. And add specific styles based on class / id selector(s), where you want to change them.
DEMO
give
.form-styling-date option{color: black;}
in main.css file at line 243.
Keep your select as white, but then override your select option as black in your case:
.form-styling-date option{
color:black;
}
You should try :
::-moz-selection { /* Code for Firefox */
color: white;}
::selection {
color: white;}
Update default style to black :)
this is problem with your CSS.
Add this CSS in your page. because this page contain three select all this color is white.
select option{
color:#000;
}

Create a segmented control-like with a draggable function

I have 2 divs positioned next to each other, and a background div. We'll call the background div "bg div". Whenever one of the 2 divs get selected, the bg div gets positioned on top of the selected div with a transition. Basically, something like a segmented controller.
The next step I want to do is, I want to make the bg div draggable. If it gets dragged, but not all the way to either side, then it should snap to whichever side the bg div is mostly at.
I'm looking for something like this:
When I set the bg div to be draggable, (using JQuery UI) it wasn't draggable. Only when I removed z-index: -1 did it become draggable. It also didn't snap to either side. It only snapped when the bg div got dragged basically all the way. Also, when I drag it, it has a weird effect to it. It waits a bit then drags. I think that's because the transition.
Problems
How can I make it draggable with of index: -1?
How can I make it snap to whichever side the bg div is mostly at?
How can I make it have a transition without working weird?
Without issues, but not draggable functionality: JSFiddle
With issues: JSFiddle
$('#bckgrnd').draggable({
axis: "x",
containment: "parent",
snap: ".labels"
});
#radios {
position: relative;
width: 370px;
}
input {
display: none;
}
#bckgrnd,
#bckgrndClear,
.labels {
width: 50%;
height: 30px;
text-align: center;
display: inline-block;
float: left;
padding-top: 10px;
cursor: pointer;
}
.labels {
outline: 1px solid green;
}
#bckgrnd {
background-color: orange;
position: absolute;
left: 0;
top: 0;
transition: left linear 0.3s;
}
#rad1:checked ~ #bckgrnd {
left: 0;
}
#rad2:checked ~ #bckgrnd {
left: 50%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="radios">
<input id="rad1" type="radio" name="radioBtn" checked>
<label class="labels" for="rad1">First Option</label>
<input id="rad2" type="radio" name="radioBtn">
<label class="labels" for="rad2">Second Option</label>
<div id="bckgrnd"></div>
</div>
Working solution: http://jsfiddle.net/6j0538cr/ (I know you wont use it :))
How can I make it draggable with of index: -1?
Add two elements one that hold the label with 'pointer-events:none;' which will ignore all mouse events and 'z-index:3',
And second that will be the 'button' and will have 'z-index:1'.
Like that you will have one label that ignores all mouse events and float above all the elements with z-index:3, and the 'background' will still be draggable
How can I make it snap to whichever side the bg div is mostly at?
You can calculate it very easily using 'offset' and 'width' functions like so
//calculating the middle of the 'background'
var backgroundX = $('#bckgrnd').offset().left;
var backgroundWidth = $('#bckgrnd').outerWidth();
var backgroundMiddle = backgroundX + (backgroundWidth/2);
//calculating the middle of the radios on the page
var radiosX = $('#radios').offset().left;
var radiosWidth = $('#radios').outerWidth();
var radiosMiddle = radiosX + (radiosWidth/2);
//compare the two
if(radiosMiddle > backgroundMiddle){
//closer to the left
}else{
//closer to the right
}
How can I make it have a transition without working weird?
You can set the transition using jQuery 'animate' instad of mixing css and js animation.
draggable with index -1: Have a container div for the whole thing (radios?) trapping mouse events. mousedown you record the mouse x value. mousemove (with button down I suppose) you calculate the "delta" from current mouse x to mousedown x, and add that to the original x value of the thing you are "dragging".
snapping: just using min / max function to limit the delta, but it sounds like some animation is there even for the "snap". So for a mouse up within a certain end zone range, fire that animation to "snap" to one side or the other.
Also, the click inside certain bounds close to the edge fires that same snap.
I've could probably done this using <input> radio elements...
But any way on submit you can send the data-* value.
Here's my take:
$(".io-toggler").each(function(){
var io = $(this).data("io"),
$opts = $(this).find(".io-options"),
$clon = $opts.clone(),
$span = $clon.find("span"),
width = $opts.width()/2;
$(this).append($clon);
function swap(x) {
$clon.stop().animate({left: x}, 150);
$span.stop().animate({left: -x}, 150);
$(this).data("io", x===0 ? 0 : 1);
}
$clon.draggable({
axis:"x",
containment:"parent",
drag:function(evt, ui){
$span.css({left: -ui.position.left});
},
stop:function(evt, ui){
swap( ui.position.left < width/2 ? 0 : width );
}
});
$opts.on("click", function(){
swap( $clon.position().left>0 ? 0 : width );
});
// Read and set initial predefined data-io
if(!!io)$opts.trigger("click");
// on submit read $(".io-toggler").data("io") value
});
.io-toggler{
cursor:pointer;
display:inline-block;
position:relative;
font:20px/1.5 sans-serif;
background:url(http://i.stack.imgur.com/XVCAQ.png);
color:#fff;
border:4px solid transparent;
border-radius: 50px;
user-select:none;
-webkit-user-select:none;
-webkit-touch-callout:none;
}
.io-options{
border-radius:50px;
top:0;
left:0;
overflow:hidden;
}
.io-options span{
position:relative;
text-align:center;
display:inline-block;
padding: 3px 35px;
}
/* the jQ clone */
.io-options + .io-options{
position:absolute;
background:#fff;
width:50%;
height:100%;
white-space:nowrap;
}
.io-options + .io-options span{
color:#006cff;
}
<link href="https://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css" rel="stylesheet" type="text/css" />
<script src="https://code.jquery.com/jquery-1.11.3.js"></script>
<script src="https://code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
<span class="io-toggler" data-io="0">
<span class="io-options">
<span>Thing1</span>
<span>Thing2</span>
</span>
</span>
<br><br>
<span class="io-toggler" data-io="1">
<span class="io-options">
<span>Yes</span>
<span>No</span>
</span>
</span>

jQuery custom checkboxes + hidden html checkbox

I'm making a grid of divs that can be toggled on and off. I need to post the values of these toggled divs to a database.
Currently I have jQuery waiting for clicks on the divs and then changing checkbox values on a hidden checkbox element...
$('.icon').click(function(){
var checkValue = $(this).attr("data-c");
// Then tick hidden checkbox where data-c = checkbox
});
As I end up posting this data with ajax, is there a better way to do this?
Here's what it looks like:
You actually don't need JS.
Use a <label> elements to wrap your checkbox and a span.
Change the style of that inner span using the input:checked next sibling selector +:
label.icon span{
cursor: pointer;
display: inline-block;
width: 75px;
height: 75px;
background:url(http://i.stack.imgur.com/ceycQ.jpg) no-repeat;
border: 3px solid #0186C9;
border-radius: 12px;
}
label.icon input{ /* hide the checkbox */
position: absolute;
visibility: hidden;
}
label.icon input:checked + span{ /* when input is checked */
background-position: 0 -75px;
}
<form action="">
<label class="icon">
<input type="checkbox" name="dog">
<span></span>
</label>
</form>
on form submit you'll submit all the correct data without a single line of JS
I've found a similar question here: Jquery Use Image As CheckBox
As an alternative to storing the value in a check box you could store it in a object? For example:
window.icons = {};
$('.icon').click(function() {
var id = $(this).data('identifier');
window.icons[id] = !!window.icons[id];
});
Also check out this example for a similar use http://jsfiddle.net/bdTX2/

Form element container heights

I'm building a form manager for my framework and want to add methods to create form elements based on parameters passed. Each "element container" has the following:
A validation row positioned at the top of the container. This row is turned off by default (display: none) and will only show if a javascript validation error occured.
A label container (situated on the left)
A form control container (situated on the right)
Here is a sample HTML:
<div class='control_container'>
<div class='validation'></div>
<div class='label_container'>
<label for=''>Label</label>
</div>
<div class='elements_container'>
<div class='element'>
<input type='text' name='' value='' />
</div>
</div>
</div>
My issue here is that I need to the control_container to seperate label and elements containers but also need the label_container and element_container to both have the same height irrespective of the content. These 2 containers may have different background colours so I need to ensure that the stretch to the bottom of the control_container and also keep in consideration that the validation div might show (so using position: absolute and top: 0 might not work).
I have tried the following:
Giving control_container a relative position and the 2 seperate containers both a position absolute. As the height of the containers would mostly be dictated by the height of the label (if the label is multiple lines or if the element_container has multiple elements within it this option does not work.
Floats (There I say more? :D)
I would prefer a CSS solution which is compatible with most browsers (including IE8 (am I pushing it to ask for IE7 haha)
Any ideas?
** ADDITIONAL INFORMATION **
I want the layout to look something like this:
--------------------- control_container ---------------------
[Potential validation message (this will be toggled on/off) ]
[label_container][ elements_container ]
------------------- end of control_container ----------------
So label_container (with the label) and elements_container (with it's elements) will be next to eachother. These 2 containers may have different background colours so they should both stretch (height) according to the biggest element. The only issue I see here is validation element which wont show by default so using absolute positioning might not work as the validation message might take the top area and have the elements overlap eachother.
HTML:
<div class="controls">
<div class="message">Test</div>
<div class="label_container">
<label for="">Label Label Label Label Label Label Label Label Label Label Label Label Label Label Label Label </label>
</div>
<div class="elements_container">
<div class="element">
<input type="text" name="test" value="" />
</div>
</div>
</div>
CSS:
.controls {
position: relative;
display: table;
width: 100%;
}
.controls .message {
background: red;
padding: 5px;
color: #FFF;
font-weight: bold;
height: 30px;
width: 100%;
display: table-caption;
box-sizing: border-box;
}
.controls .label_container {
display: table-cell;
background: #D3D3D3;
width: 150px;
height: 100%;
margin-top: 30px;
}
.controls .elements_container {
display: table-cell;
background: #A2A7DD;
color: #000;
width: 650px;
height: 100%;
margin-top: 30px;
margin-left: 150px;
}
All of them here in jsFiddle: Demo

Categories

Resources