How to make input pop out and show whole content - html

I have multiple inputs and for some of them the input is to small to display the whole text (can not be changed). Is there a way to show the whole content of the input when hovering without breaking the rest of the layout? I included an example. I am trying to have the input pop out and be on top of the other inputs without breaking the design.
https://jsfiddle.net/14e37gj0/
I am not realy good with css.
I tried something like this.
input {
width: 10%;
}
input:hover {
width: 100%;
}
Best regards

First way to come on my mind was using Flexbox
so first of all, you need to wrap all your input tags with a wrapper like this
<div class="wrapper">
<input type="text" value="This text is long and I want to see the whole input when hovering" />
<input type="text" />
<input type="text" />
<input type="text" />
</div>
And in CSS add the following rules
.wrapper {
display: flex;
}
input:hover {
flex: 1 1 auto;
}
The flex: 1 1 auto is the one responsible to fill remaining gap until the end of the row.
Things could still be more efficient, but i tried to make it as simple as possible, and i suggest you learn more about CSS Flexbox.

Wrap the inputs in a flexbox div:
.row{
display:flex;
width:100%;
}
input {
width: 10%;
}
input:hover {
width: 100%;
}
<div class="row">
<input type="text" value="This text is long and I want to see the whole input when hovering"/>
<input type="text" />
<input type="text" />
<input type="text" />
</div>

You can use javascript to create a mouseover and mouseout event to create an absolutely positioned element, then pass the value of the event.target into its content. Use insertAdjacentHTML to add it on mouseover and use .remove() to remove it on mouseout. Check the inputs clientWidth with the inputs scrollWidth to see if you have overflow, if you do, insertAdjacentHTML span tag with class of .content with the e.target.value as its content.
See below code in snip it with full explanation of code above each line:
// get nodelist of all inputs
let inputs = document.querySelectorAll('input')
// function for the event listeners, pass the event into it as poarameter => e
function showAllContent(e) {
// the following positions will be used to position our
// absolutely positioned span tag below the event.target element
// get the top position of the event target => "input" being hovered
let top = e.target.getBoundingClientRect().top
// get the left position of the event target => "input" being hovered
let left = e.target.getBoundingClientRect().left
// get the height of the event target => "input" being hovered
let height = e.target.getBoundingClientRect().height
/* set a root variable for e.target top and left to be used in CSS to style
the position of the absolutely positioned span tag
NOTE: if you change the inputs layout of have elements below,
you will likely have to play with these settings a bit */
document.documentElement.style.setProperty('--e-target-top', `${top + height}px`)
document.documentElement.style.setProperty('--e-target-left', `${left}px`)
// set variable for event target value
let allContent = e.target.value.trim()
// set variable to show all of event.target.value
let span = `<span class="content">${allContent}</span>`
// conditional to make sure event.target is not null and also
// make sure its scrollWidth is greater than its clientWidth
if (allContent && e.target.scrollWidth > e.target.clientWidth) {
// check type of event is mouseover
if (e.type === 'mouseover') {
// insert the span tag into the DOM
e.target.insertAdjacentHTML('afterend', span)
}
// check type of event is mouseout and .content is set
if (e.type === 'mouseout' && document.querySelector('.content')) {
// remove the element from DOM
document.querySelector('.content').remove()
}
}
}
// iterate over the input nodeList
inputs.forEach(input => {
// event listener for mouseover
input.addEventListener('mouseover', showAllContent)
// event listener for mouseout
input.addEventListener('mouseout', showAllContent)
})
:root {
/* this will set our top position in the .content class it is being sent
from JS using style.setProperty('--e-target-top', `${top + height}px`) */
--e-target-top: 0;
/* this will set our left position in the .content class it is being sent
from JS using style.setProperty('--e-target-left', `${left}px`) */
--e-target-left: 0;
}
input {
width: 10%;
}
.content {
display: inline-block;
position: absolute;
left: var(--e-target-left);
top: var(--e-target-top);
width: auto;
height: auto;
background: #ccc;
border-radius: .5rem;
padding: .5rem;
margin-top: 2px;
}
<div id="parent">
<input type="text" value="This text is long and I want to see the whole input when hovering" />
<input type="text" value="small text" />
<input type="text" value="this inputs scrollWidth will overflow the clientWidth" />
<input type="text" />
</div>

Related

Changing/Styling individual input elements in HTML

Is there anyway to target specific input text elements in a form and reposition it, because it's letting me do things such as adjust padding, but I cannot reposition it by using margin. I also can't change the color, unless I do a style on the label. But doing a color on the label is useless because there's still the color in the input that I want to change. In short, I don't know how to override the original rule that I have for my input elements. Margins are not working either.
code:
input[type=text] {
width: 75%;
padding: 12px 20px;
margin: 8px 0;
display: inline-block border: 1px solid #ccc;
border-radius: 4px;
color: #ffb3ec;
font-size: 24px;
box-sizing: border-box;
background-color: #4d4100;
}
.sample {
width: 30px;
background-color;
green;
}
<div class="mainBox">
<form>
<fieldset>
<label>placeholder:
<input type="text" id="placeholder" name="placeholder">
</label>
<br>
<label>Targets
<input type="text" class="sample" name="sample">
</label>
</fieldset>
</form>
</div>
You can wrap your input into a div element like below and reposition that:
<div class = "mainBox" >
<form>
<fieldset>
<div class = "wrapper">
<label> placeholder: </label>
<input type = "text" id = "placeholder" name = "placeholder" >
</div>
<br>
<div class = "wrapper">
<label> Targets </label>
<input type = "text" class = "sample" name = "sample" >
</div>
</fieldset>
</form>
</div>
I have rearranged the code a bit to fix the colour problem. It occurred, because you wrapped your input element inside the label. It doesn't work this way. Also remember to use for = "[THE ID OF YOUR INPUT ELEMENT]" to bind them together like so:
<label for = "sample"> Targets </label>
<input id = "sample" type = "text" class = "sample" name = "sample" >
In addition, before trying to play with top, bottom, left, right, paddings and margins always define the position of the element, because the default position is set to static, which means it isn't supposed to be moved.
position: static /* default, not supposed to be moved */
position: relative; /* to have move around its relative area */
position: absolute; /* to have move around based on the parent element */
position: fixed; /* to have move around based on the body of the document */

Make input element auto-size like a span

A <span> knows what horizontal size to be without being told. It's horizontal size is no greater than its content.
I'm trying to figure out the CSS to make an <input type='text'> automatically size itself horizontally according to the length of its value, like a <span> would with its innerText.
In other words, without specifying a CSS width: or size attribute on the <input>.
I can't figure out how to do this. Any ideas?
If you want to expand or increase the width of input field as you type you could do something like this
<div>
<span contenteditable="true">sdfsd</span>
</div>
CSS
span{
border: solid 1px black;
}
div{
max-width: 200px;
}
JSFiddle Demo
Or You could accomplish this using some jQuery
<input size="1" />
jQuery
$('input').on('keydown', function(evt) {
var $this = $(this),
size = parseInt($this.attr('size'));
if ( evt.which === 8 ) {
// backspace
$this.attr('size', size - 1);
} else {
// all other keystrokes
$this.attr('size', size + 1);
}
});
JSFiddle Demo
If I understand your question correctly, you want the span and input to be the same width no matter what, correct?
If this is the case then this is the way I would go about it:
Wrap both the span and input with a div
then,
span, input {
display: inline-block;
width: 100%;
}
And set your wrapping div to whatever width you want and the two elements should be aligned (automatically, no matter what) and the same width.

Clone CSS styled file upload buttons

I styled an <input type="file"/> using CSS. When I click on a + button, it will be cloned. However this does only visually happen with an unstyled upload button.
Hint: In order to replace the standard button with a styled one, I set input[type="file"] { display:none }. Commenting this line out, the cloned upload buttons become visible, however without styles.
Is there a way to clone CSS styled buttons?
See Fiddle
You'll need to clone the label in addition to the input.
This clones the first label, while ensuring that it works with its own input:
$('label').first()
.clone(true)
.attr('for','img'+addcounter)
.insertBefore($('#add'));
Fiddle
Reconfigure your HTML, then clone the label
Form elements such as input can be children of label elements (w3.org, 17.9.1 The LABEL element), and doing so will make it easier to clone both with one statement.
Below, I do this and then assign the id attribute to the parent label for easier targeting.
<label id="img1" class="uploadbutton">Choose File
<input type="file" name="img1"/>
</label>
Note: You could leave the id attribute on the input and simply use jQuery's .parent() method to get the label if you prefer. There is more than one way to paint a fence.
The script then clones the label and its children in one statement. Notice the addition of .find(input) to set the attributes on the child input.
Example:
var addcounter = 2;
$("#add").on('click', function (e) {
//Create a new select box
$('#img1')
.clone()
.attr({
id: "img" + addcounter
})
.insertBefore($('#add'))
.find("input")
.attr({
name: "img" + addcounter
});
addcounter++;
});
td {
width: 100px;
}
input[type='file'] {
display: none;
}
#img2 {
color: red;
}
#img3 {
color: blue;
}
.uploadbutton {
margin-right: 25px;
padding: 6px 15px 6px 15px;
cursor: default;
color: #000;
font-size: 15px;
text-align: center;
border: 1px solid #000;
border-radius: 20px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<label id="img1" class="uploadbutton">Choose File
<input type="file" name="img1"/>
</label>
<button id="add">+</button>
Update:
There is an additional benefit to nesting input elements within label elements, which is that you can freely position the parent label while the child input inherits that positioning by default.
The input then can be relatively or absolutely positioned within it, which is easier than trying to manage the position of two independent siblings and better than applying an unnecessary container element to achieve the same effect.
You don't need to make use of that benefit in this example, but I felt it was worth stating for good measure.
You are not styling the input at all, you are styling the label, and then only cloning the input. Try also cloning the label.
I think you might want to adapt this for type="file"

tabIndex doesn't make a label focusable using Tab key

I'm trying to replace checkbox/radio inputs with icons. For this, I need to hide the original checkbox/radio. The problem is, I also want the form to properly support keyboard input, i.e. let the input remain focusable by Tab key and selectable using Spacebar. Since I'm hiding the input, it cannot be focused, so instead, I'm trying to make its <label> focusable.
This documentation and various other sources led me to believe I can do that using tabindex attribute (corresponding to HTMLElement.tabIndex property). However, when I try to assign tabindex to my label, it remains as unfocused as ever, however much I try to Tab to it.
Why doesn't tabindex make the label focusable?
The following snippet demonstrates the issue. If you focus the input with your mouse and try focusing the label using Tab, it doesn't work (it focuses the following <span> with tabindex instead).
document.getElementById('checkbox').addEventListener('change', function (event) {
document.getElementById('val').innerHTML = event.target.checked;
});
<div>
<input type="text" value="input">
</div>
<div>
<label tabindex="0">
<input type="checkbox" id="checkbox" style="display:none;">
checkbox: <span id="val">false</span>
</label>
</div>
<span tabindex="0">span with tabindex</span>
(The JavaScript code just allows to see that clicking on the label properly (un)checks the checkbox.)
Why doesn't tabindex make the label focusable?
Short Answer:
Label is focusable.
TabIndex won't make any difference.
Welcome to the world of browser/agent inconsistencies.
tl;dr;
The label (Ref) element is very much focusable. Its DOM Interface is HTMLLabelElement which derives from HTMLElement (Ref) which in turn implements GlobalEventHandlers (Ref) and hence exposes the focus() method and onfocus event handler.
The reason you are unable to get hold of proper specification / reference document for labels focus behaviour, is because you might have been looking at HTML5 Specs. Interestingly, HTML5 refs do not state anything relating to that, which adds to the confusion.
This is mentioned in the HTML 4.01 Ref here: http://www.w3.org/TR/html401/interact/forms.html#h-17.9.1
Specifically near the end of section 17.9.1 and just before 17.10:
When a LABEL element receives focus, it passes the focus on to its
associated control.
Also, elsewhere (I am unable to get hold of that part of the ref) I have read that it depends on the implementing agent. (Don't take my word for that, am not too sure).
However, what it means is that when you focus a label (or a label received a focus), that focus is passed on to its associated labeleable control. This will not result in two different focuses, but one focus on the input (in your case a checkbox). Because of this behaviour, tabindex property cannot play a role.
There is also a test suite by W3C for website accessibility (WAAG) here: http://www.w3.org/WAI/UA/TS/html401/cp0102/0102-ONFOCUS-ONBLUR-LABEL.html which, discusses the implementation of onfocus and onblur for a label. Ideally a keyboard or an assistive technology that emulates the keyboard should implement this. But...
This is where the browser inconsistencies play their role.
This can be demonstrated by this example. Check the following snippet in different browsers. (I have tested it against IE-11, GC-39 and FF-34. All of them behave differently.)
Click the button "Focus Label"
It should focus the label, then pass the focus and highlight its associated checkbox outline in blue.
Chrome-v39 works. IE-v11 it doesn't (somehow html and body do respond to :focus). FF-v34 it works.
Talking about browser inconsistencies, try using the "access key" L. Some browsers will focus the checkbox whereas some will click it i.e. pass the action to it.
Here is a fiddle to test it: http://jsfiddle.net/abhitalks/ff0xds4z/2/
Here is a snippet:
label = $("label").first();
$("#btn").on("click", function() {
label.focus();
});
* { margin: 8px; }
.highlight { background-color: yellow; }
:focus {
outline: 2px solid blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="txt" type="text" value="input" /><br />
<label for="chk" accesskey="L">Checkbox: </label>
<input id="chk" type="checkbox" /><br />
<input id="btn" type="button" value="Focus Label" />
Hope that clears up your doubts.
.
Your problem:
Now focussing (sic) on your original problem of not being able to focus a label, because you want to style a checkbox differently by placing an icon kind of thing in its place.
In order to do that, one option for you is to not hide it completely by doing a display:none;. Rather, make it 1x1 pixel and shove it under your icon. This way it will still receive focus naturally and yet be effectively hidden.
For example, if your icons are a checkmark and a cross, then change the position of the checkbox and make the icons out of ::before or ::after pseudo-elements on the label. That will cause the checkbox to still receive focus, and make the icon respond to that. That will give the apparent illusion of the icon taking the focus.
Demo Fiddle: http://jsfiddle.net/abhitalks/v0vxcw77/
Snippet:
div.chkGroup { position: relative; }
input#chk {
position: absolute;
width: 1px; height: 1px;
margin: 0; margin-top: 4px; outline: none;
border: 1px solid transparent; background-color: transparent;
}
label::before {
content: '\2714';
position: relative;
width: 18px; height: 18px;
background-color: #fff;
margin-right: 8px; padding: 2px;
display: inline-block;
border: 1px solid transparent;
}
input#chk:checked + label::before {
content: '\2716';
}
input#chk:focus + label::before {
border: 1px solid #00f;
}
<input id="txt" type="text" value="input" /><br /><br />
<div class="chkGroup">
<input id="chk" type="checkbox" />
<label for="chk" accesskey="L">Checkbox</label>
</div>
.
Since this old post is one of the top google results for html label tabindex I want to add my very simple working solution. As #Abhitalks mentioned in the accepted answer, the focus of a label is passed to it's associated control. So to bypass this behavior, just add a tabindex to the label and use event.preventDefault() in a focus EventListener.
#Heretic Monkey kind of had the right idea in his answer but you don't need a wrapper element to achieve this. You will, however, need to manually forward any required keystrokes (like spacebar) through.
For example:
'use strict';
let field = document.getElementById('hidden-file-chooser');
let label = document.querySelector('label[for=hidden-file-chooser]');
// prevent focus passing
label.addEventListener('focus', event => {
event.preventDefault();
});
// activate using spacebar
label.addEventListener('keyup', event => {
if (event.keyCode == 32) {
field.click();
}
});
#hidden-file-chooser {
display: none;
}
input[type=text] {
display: block;
width: 20rem;
padding: 0.5rem;
}
label[for=hidden-file-chooser] {
display: inline-block;
background: deepskyblue;
margin: 1rem;
padding: 0.5rem 1rem;
border: 0;
border-radius: 0.2rem;
box-shadow: 0 0 0.5rem 0 rgba(0,0,0,0.7);
cursor: pointer;
}
<input type="text" placeholder="Click here and start tabbing through ...">
<input id="hidden-file-chooser" type="file">
<label for="hidden-file-chooser" tabindex="0"> Select a File </label>
<input type="text" placeholder="... then shift+tab to go back.">
P.S: I used input[type=file] in my example because that's what I was working on when I ran across this issue. The same principles apply to any input type.
Edit: The following was a misreading of the spec:
Looking that the full
specification,
you'll see that there is something called tabindex focus
flag,
which defines if the tabindex attribute will actually make the field
"tabbable". The label element is missing from that list of suggested
elements.
But then again, so is the span element, so go figure :).
That said, yYou can make the label text focusable by wrapping the whole thing in an another element, or using some JavaScript to force the issue. Unfortunately, wrapping (here in an anchor) can men a fair amount of extra work in CSS and JS to get working like a normal label element.
document.getElementById('checkbox').addEventListener('change', function(event) {
document.getElementById('val').innerHTML = event.target.checked;
});
document.getElementsByClassName('label')[0].addEventListener('click', function(event) {
event.target.getElementsByTagName('label')[0].click();
event.preventDefault();
});
document.getElementsByClassName('label')[0].addEventListener('keypress', function(event) {
if ((event.key || event.which || event.keyCode) === 32) {
event.target.getElementsByTagName('label')[0].click();
event.preventDefault();
}
});
.label,
.label:visited,
.label:hover,
.label:active {
text-decoration: none;
color: black;
}
<div>
<input type="text" value="input">
</div>
<div>
<a class="label" href="#">
<label tabindex="0">
<input type="checkbox" id="checkbox" style="display:none;">checkbox: <span id="val">false</span>
</label>
</a>
</div>
<span tabindex="0">span with tabindex</span>
As previous posters said:
Label focus always goes directly to the input element.
Quite an annoyance if somebody has fancy (but fake) checkboxes, hiding the original ones, with an actual focus for keyboard navigation nowhere to be seen.
best solution I can think of: javascript.
Style-away the actual focus, in favor of a fake one:
input[type=checkbox]:focus {
outline: none;
}
.pseudo-focus {
outline: 2px solid blue;
}
and watch for changes on the (in many scenarios visibly hidden) original checkbox:
$('input[type=checkbox')
.focus( function() {
$(this).closest('label').addClass('pseudo-focus');
})
.blur( function() {
$(this).closest('label').removeClass('pseudo-focus');
});
Full jsfiddle here.
For input type radio or checkbox:
opacity: 0;
height: 0;
width: 0;
min-height: 0;
line-height: 0;
margin: 0;
padding: 0;
border: 0 none;
and the Js above does the trick sweetly.

IE 11 Bug - Image inside label inside form

In IE11, the following piece of code will check the radio button as expected:
<input type="radio" id="myRadio" />
<label for="myRadio">
<img src="..." />
</label>
Wrapping a <form> around the above will however break the functionality of the label.
This SO post offers a solution to the problem by styling the image with pointer-events:none, and the label as a block-level element.
While that should of course not even be necessary, it also disables the ability to handle mouse events.
It would be much appreciated if someone can offer a pure CSS solution to this problem.
PS:
One thing worth mentioning, is that in IE11, if the image is styled as a block-level element, then pointer-events seems to loose its effects.
My markup looks like this (classes and other superfluous attributes removed):
<li>
<label>
<figure>
<img>
</figure>
<div>
<label></label>
<input type="radio">
</div>
</label>
</li>
It's a bit messy because some of it is auto-generated by Drupal. It didn't work in IE 11, but I made it work by adding:
img {
pointer-events: none;
}
I didn't need to change anything else and I have no other special css-trickery that I can see.
As I answered previously in the referred question, there is a pure CSS way.
If your image is display: block that fix can still be used, even tho you have to add some more trickery. For example:
CSS:
label img{
display: block; /* requirement */
/* fix */
pointer-events: none;
position: relative;
}
/* fix */
label{
display: inline-block;
position: relative;
}
label::before{
content: "";
display: block;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: -1;
}
HTML:
<form>
<label>
<input type="checkbox"> some text
<img src="http://placekitten.com/200/200" alt="kitten!">
</label>
</form>
Fiddle
If the problem is with click handlers on the image it self, you may be able to solve that with a wrapper element on the image instead (which maybe the label, so no extra element may be needed). (But for that I'd like to see a more specific example that you are trying to do.)
img {
pointer-events: none;
position: relative;
z-index: -1;
}
This solved it in my case.
The img will be placed behind the label but "shine through".
I hope it helps.
You can put the image in the background of the label..
<label for="myField1" ><img src="image1.jpg"></label>
becomes
<style>
#lblMyField1 {
background-image: url('image1.jpg');
background-position: center center;/* depend..*/
background-repeat: no-repeat;
}
</style>
<label id="lblMyField1" for="myField1" > </div>
This is a rather interesting find. I'll do a bit more research to determine whether or not I can identify a more root cause, but for the time being I have a couple suggestions.
Nest Your Input
<label>
<input />
<img />
</label>
This is a common convention used for associating inputs with labels. Given the input and the label are both inline, this doesn't affect the actual layout necessarily.
JavaScript Patch
Another option is to perform a click on the corresponding input when one didn't happen naturally. In this approach we setup a timeout to click after 100ms. Any click that happens otherwise will clear our timeout:
$("label[for]").each(function () {
var timeout;
var element = $("#" + $(this).attr("for"));
$(this).on("click", function () {
timeout = setTimeout(function () {
element.click();
}, 100);
});
element.on("click", function () {
clearTimeout(timeout);
});
});
Browsers that already work will clear the timeout, preventing a second click. Internet Explorer 11 will click via the timeout.
Demo: http://jsfiddle.net/CG9XU/
One caveat is that that solution only works for labels that were on the page when the case was ran. If you have forms coming in late (perhaps via ajax), you'll need to listen higher up on the DOM. The below example listens on the document level:
$(document).on("click", "label[for]", function () {
var timeout;
var element = $("#" + $(this).attr("for"));
timeout = setTimeout(function () {
element.click();
}, 100);
element.one("click", function () {
clearTimeout(timeout);
});
});
The label element accepts as its content type all phrasing elements, and this includes image elements. I'll keep looking into this, and will update this answer with any insight.
Here is a solution that worked for me using pointer-events:none without having to set my image to position:relative as I needed it to be position:absolute for my design.
HTML
`<form>
<input id="radio-button-action" type="radio" name="search" value="open">
<label for="radio-button-action">
<div class="img-wrapper">
<img src="images/image.jpg" alt="image">
</div>
</label>
</form>`
CSS
So in this example we have an image that needs to be position: absolute
img {
position: absolute
top: 10px;
right: 10px;
height: 25px;
width: 25px;
display: inline-block; /* can be block, doesn't matter */
}
Now set pointer-eventson the img-wrapper div
.img-wrapper {
position: relative /* this is required for this to work */
pointer-events: none /* this is what will make your image clickable */
}
It works with
img {
pointer-events: none;
}