I've created my own custom file upload button by creating a label and hiding the input element with css. This all works fine, but the problem is I can't use the button by tabbing and enter. I tried adding tabindex=0 to the label. I could then tab to the element ok but there was no action when clicking enter as it is only a label.
Here is the HTML code
<label class="custom-file-upload>
<input type="file">
Choose file
</label>
and css to hide the default file upload button
input[type="file"] {
display: none;
}
Any help is much appreciated.
This can all be achieved with CSS on modern browsers with the added benefit that:
there is no reliance on JavaScript
there is no need for a tabindex
it activates with space or enter, both of which are expected behaviours.
The key is to make the input visually hidden (using the .visually-hidden class) but still focusable and then use the + to link the label (without wrapping the input in the label).
The key part of the example below is [type="file"]:focus + label
This lets you change the label styling when the input is selected (it is important that the <label> appears immediately after the <input> in the DOM in order for this to work).
I also included the syntax for applying a ::before styling on hover and focus for completeness.
Example (not a production ready solution)
The example given below was a quick and dirty way of demonstrating how to achieve your goal, it has a couple of accessibility issues that need addressing before putting it into production:-
you shouldn't use the same styling for hover and focus -> hover you should change colour and show the icon, focus add a border and show the icon
instead of using a font for the icon you should use an SVG as fonts may break if someone overrides them (i.e. if they have a preferred font due to dyslexia).
make sure that you disable animation of the icon entering if people have indicated they prefer reduced movement by using the prefers-reduced-motion: reduce media query https://developer.mozilla.org/en-US/docs/Web/CSS/#media/prefers-reduced-motion
Also make sure you associate the label with the input using for="inputName" on the label and id="inputName" on the input.
.visually-hidden {
position: absolute !important;
height: 1px;
width: 1px;
overflow: hidden;
clip: rect(1px, 1px, 1px, 1px);
white-space: nowrap;
}
[type="file"] + label {
background: #f15d22;
border: none;
border-radius: 5px;
color: #fff;
cursor: pointer;
display: inline-block;
font-size: inherit;
font-weight: 600;
margin-bottom: 1rem;
outline: none;
padding: 1rem 50px;
position: relative;
transition: all 0.3s;
vertical-align: middle;
background-color: #99c793;
border-radius: 50px;
overflow: hidden;
}
[type="file"] + label::before {
color: #fff;
content: "\f382";
font-family: "Font Awesome 5 Pro";
font-size: 100%;
height: 100%;
right: 130%;
line-height: 3.3;
position: absolute;
top: 0px;
transition: all 0.3s;
}
[type="file"]:hover + label,
[type="file"]:focus + label{
background-color: #497f42;
}
[type="file"]:hover + label::before,
[type="file"]:focus + label::before {
right: 75%;
}
<link rel="stylesheet" href="https://pro.fontawesome.com/releases/v5.2.0/css/all.css" />
<input type="file" id="inputName" class="visually-hidden"/>
<label for="inputName">upload</label>
You can rewrite your code something in this manner
<input id="file-upload" type="file">
<label for="file-upload" class="custom-file-upload>Choose file</label>
CSS for input and change css for label accordingly using sibling selector
input[type="file"] {
opacity: 0;
}
With labels you need to trigger click on keyboard events for enter
<label for ="file-upload1" tabindex="0" class="custom-file-upload">
<input type="file" id="file-upload"/> Choose file
</label>
CSS
input[type="file"]{
display:none;
}
JQuery Code
$('.custom-file-upload').on('keyup',function(event){
if (event.keyCode === 13) {
$('#file-upload').trigger('click');
}
})
I may have a little hack that can help. You can use the focus-within attribute on your parent element that holds your file input and style it with this
parent:focus-within {
border: 1px solid blue;
background: yellow;
}
Related
I have a project where sometimes checkboxes don't have labels. The only way of setting custom image for checkbox I've found was setting image for label:before for corresponding label which has for value with id of checkbox.
Are there any CSS way (at least hacky) to set custom image to checkbox without changing markup? input[type="checkbox"]:before works only in Chrome.
The only way I've found that works everywhere except IE is via setting CSS appearance:
input[type="checkbox"] {
width: 16px;
height: 16px;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
background-color: red;
}
input[type="checkbox"]:checked {
background-color: green;
}
<input type="checkbox" />
I think it's impossible to do it without label for all browsers. In my opinion label is necessarily.
But you can use JS for this and one of library like icheck (and many other not only jQuery also pure JS)
Maybe if you add a container to your checkbox like this
<div>
<input type="checkbox">
</div>
and then
div{
position: relative;
/* Your custom style */
}
input{
position: absolute;
height: 100%;
width: 100%;
left: 0;
top: 0;
opacity: 0;
}
I wanted to use custom checkboxes on a website so for starters, I worked with a span that I gave a custom background-color and once checked, I changed the background-color in CSS and this worked fine, the background-color changed when the checkbox was clicked on. However, once I replaced the color values by an image background url, it shows the background image in the initial state but it won't change the background-image after the value is checked. The checkbox flashes for a brief time but then continues to have the original background image.
The URL is correct, I can open the image in my browser. I've tried by giving the label rather than the span inside it the background properties but this has the same result. In the inspector in Google Chrome, the new background property is also 'active' (and the old one 'crossed out') so I just can't understand why it continues to show the old one.
The HTML:
<input type="checkbox" id="unlimited" name="unlimited" value="unlimited" />
<label for="unlimited"><span></span>Unlimited amount</label>
CSS:
input[type="checkbox"] {
display:none;
}
input[type="checkbox"] + label span {
display:inline-block;
width:30px;
height:30px;
margin:-1px 4px 0 0;
vertical-align:middle;
background: url("../../static/img/checkbox1.jpg");
cursor:pointer;
}
input[type="checkbox"]:checked + label span {
background: url("../../static/img/checkbox2.jpg");
}
Edit: Fixed typo. Here is the code with just background colors, which works as you'd expect, once clicked the color changes to green, you click again it changes to blue.
CSS:
input[type="checkbox"] {
display:none;
}
input[type="checkbox"] + label span {
display:inline-block;
width:30px;
height:30px;
margin:-1px 4px 0 0;
vertical-align:middle;
background: blue;
cursor:pointer;
}
input[type="checkbox"]:checked + label span {
background: green;
}
You have a typo
.input[type="checkbox"] + label span
See the full-stop/period in front of input?
input[type="checkbox"] {
display: none;
}
input[type="checkbox"] + label>span {
display: inline-block;
width: 30px;
height: 30px;
margin: -1px 4px 0 0;
vertical-align: middle;
background-image: url(http://lorempixel.com/output/abstract-q-c-30-30-4.jpg);
cursor: pointer;
}
input[type="checkbox"]:checked + label span {
background: url(http://lorempixel.com/output/people-q-c-30-30-3.jpg);
}
<input type="checkbox" id="unlimited" name="unlimited" value="unlimited" />
<label for="unlimited"><span></span>Unlimited amount</label>
The text in your question sounds like you're accidentally double clicking. But a checkbox doesn't have a double click event, so you're simply clicking twice, unselecting the checkbox the second time.
However, the code in your question shows an error in the CSS for the unchecked one, namely a extraneous dot in front of the input. If I remove that, it works normally.
(Note that I needed to replace the images by something generic.)
input[type="checkbox"] {
display: none;
}
input[type="checkbox"] + label span {
display: inline-block;
width: 30px;
height: 30px;
margin: -1px 4px 0 0;
vertical-align: middle;
background: url("http://dummyimage.com/30/FF0/000.png&text=%20");
cursor: pointer;
}
input[type="checkbox"]:checked + label span {
background: url("http://dummyimage.com/30/FF0/000.png&text=✔");
}
<input type="checkbox" id="unlimited" name="unlimited" value="unlimited" />
<label for="unlimited"><span></span>Unlimited amount</label>
I bought a bootstrap template, the style sheet file, has this code:
input[type=checkbox],
input[type=radio] {
opacity: 0;
position: absolute;
left: -9999px;
z-index: 12;
width: 18px;
height: 18px;
cursor: pointer;
}
I have a html table that has a cell with a checkbox, that is not showing up, with chrome inspector, I modified turn off the styling properties,
My question Is there any way that I could tell my code not to apply that style in the checkbox that is inside the table cell??
thanks
Alberto
yes, specifically call that check box add a class to the checkbox something like this <input type="checkbox" class="unique-class"/> then in your css add the style to just that checkbox with something like this
input.unique-class[type=checkbox],
input.unique-class[type=radio] {
/*stuff here*/
}
input[type="radio"], input[type="checkbox"] {
/*stuff here*/
cursor:pointer;
}
Is it possible to place a negating pseudo class with a user-action pseudo class?
For example:
a:hover:not(href) {
color: blue;
}
// or //
a:not(href):hover {
color: blue;
}
// or //
a:not(href) {
&:hover {
color: blue:
}
}
Here, the hover state of a link would turn the color blue if it did not have a "href".
I am trying to use this with "input[type="radio"]" and change the hover state of the radio if it is not checked (:checked). I know this kind of sounds like an if else statement with CSS, and I guess that's what I am trying to slightly accomplish without having to use js.
This may not help (always a good start to an answer), but if you control the HTML, then there's definitely a way. I tried what you'd expect the code to be...
input[type="radio"]:not(:checked):hover {
/* styles */
}
...but that didn't work. It was flickering and rubbish.
So, the only way I could think of was to have a relatively positioned container, and then absolutely position two elements inside it, a label and the input, and then have the input styles changed when you hover on the label. Using z-index we can bring the label above the input box. Then, because of the for attribute, we can make sure that the checkbox is still checked when the label is clicked.
The style I've changed on hover is the margin-top, which will pull the radio button up.
HTML
<span>
<label for="radio1">Click me</label>
<input id="radio1" type="radio" />
</span>
<span>
<label for="radio2">Click me</label>
<input id="radio2" type="radio" checked />
</span>
CSS
span {
position: relative;
display: inline-block;
min-width: 13px;
}
label, input {
position: absolute;
top: 0;
left: 0;
display: inline-block;
margin: 0;
}
label {
z-index: 2;
text-indent: -999em;
width: 13px;
height: 13px;
}
input {
z-index: 1;
}
label:hover + input[type="radio"]:not(:checked) {
margin-top: -10px;
}
Demo
http://jsbin.com/ifArIn/3/edit
Is there a way to hide the browse button and only leave the text box that works in all browsers?
I have tried setting the margins but they show up different in each browser
No, what you can do is a (ugly) workaround, but largely used
Create a normal input and a image
Create file input with opacity 0
When the user click on the image, you simulate a click on the file input
When file input change, you pass it's value to the normal input (so user can see the path)
Here you can see a full explanation, along with code:
http://www.quirksmode.org/dom/inputfile.html
You may just without making the element hidden, simply make it transparent by making its opacity to 0.
Making the input file hidden will make it STOP working. So DON'T DO THAT..
Here you can find an example for a transparent Browse operation;
.dropZoneOverlay, .FileUpload {
width: 283px;
height: 71px;
}
.dropZoneOverlay {
border: dotted 1px;
font-family: cursive;
color: #7066fb;
position: absolute;
top: 0px;
text-align: center;
}
.FileUpload {
opacity: 0;
position: relative;
z-index: 1;
}
<div class="dropZoneContainer">
<input type="file" id="drop_zone" class="FileUpload" accept=".jpg,.png,.gif" onchange="handleFileSelect(this) " />
<div class="dropZoneOverlay">Drag and drop your image <br />or<br />Click to add</div>
</div>
I find a good way of achieving this at Remove browse button from input=file.
The rationale behind this solution is that it creates a transparent input=file control and creates an layer visible to the user below the file control. The z-index of the input=file will be higher than the layer.
With this, it appears that the layer is the file control itself. But actually when you clicks on it, the input=file is the one clicked and the dialog for choosing file will appear.
Below code is very useful to hide default browse button and use custom instead:
(function($) {
$('input[type="file"]').bind('change', function() {
$("#img_text").html($('input[type="file"]').val());
});
})(jQuery)
.file-input-wrapper {
height: 30px;
margin: 2px;
overflow: hidden;
position: relative;
width: 118px;
background-color: #fff;
cursor: pointer;
}
.file-input-wrapper>input[type="file"] {
font-size: 40px;
position: absolute;
top: 0;
right: 0;
opacity: 0;
cursor: pointer;
}
.file-input-wrapper>.btn-file-input {
background-color: #494949;
border-radius: 4px;
color: #fff;
display: inline-block;
height: 34px;
margin: 0 0 0 -1px;
padding-left: 0;
width: 121px;
cursor: pointer;
}
.file-input-wrapper:hover>.btn-file-input {
//background-color: #494949;
}
#img_text {
float: right;
margin-right: -80px;
margin-top: -14px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body>
<div class="file-input-wrapper">
<button class="btn-file-input">SELECT FILES</button>
<input type="file" name="image" id="image" value="" />
</div>
<span id="img_text"></span>
</body>
Came across this question and didn't feel like any of the answers were clean. Here is my solution:
<label>
<span>Select file</span>
<input type="file" style="display: none">
</label>
When you click the label the select file dialog will open. No js needed to make it happen.
You can style the label to look like a button.
Here is an example using w3css and font awesome:
<label class="w3-button w3-blue w3-round">
<span><i class="fas fa-image"></i></span>
<input type="file" style="display: none" >
</label>
Of course you need to add an event listener to the input to detect a file was chosen.
HTML - InputFile component can be hide by writing some css.
Here I am adding an icon which overrides inputfile component.
<label class="custom-file-upload">
<InputFile OnChange="HandleFileSelected" />
<i class="fa fa-cloud-upload"></i> Upload
</label>
css-
<style>
input[type="file"] {
display: none;
}
.custom-file-upload {
border: 1px solid #ccc;
display: inline-block;
padding: 6px 12px;
cursor: pointer;
}
</style>
So I found this solution that is very easy to implement and gives a very clean GUI
put this in your HTML
<label class="att-each"><input type="file"></label>
and this in your CSS
label.att-each {
width: 68px;
height: 68px;
background: url("add-file.png") no-repeat;
text-indent: -9999px;
}
add-file.png can be any graphic you wish to show on the webpage. Clicking the graphic will launch the default file explorer.
Working Example: http://www.projectnaija.com/file-picker17.html
Just an additional hint for avoiding too much JavaScript here: if you add a label and style it like the "browse button" you want to have, you could place it over the real browse button provided by the browser or hide the button somehow differently. By clicking the label the browser behavior is to open the dialog to browse for the file (don't forget to add the "for" attribute on the label with value of the id of the file input field to make this happen). That way you can customize the button in almost any way you want.
In some cases, it might be necessary to add a second input field or text element to display the value of the file input and hide the input completely as described in other answers. Still the label would avoid to simulate the click on the text input button by JavaScript.
BTW a similar hack can be used for customizing checkboxes or radiobuttons. by adding a label for them, clicking the label causes to select the checkbox/radiobutton. The native checkbox/radiobutton then can be hidden somewere and be replaced by a custom element.
Just add negative text intent as so:
input[type=file] {
text-indent: -120px;
}
before:
after:
Oddly enough, this works for me (when I place inside a button tag).
.button {
position: relative;
input[type=file] {
color: transparent;
background-color: transparent;
position: absolute;
left: 0;
width: 100%;
height: 100%;
top: 0;
opacity: 0;
z-index: 100;
}
}
Only tested in Chrome (macOS Sierra).
the best way for it
<input type="file" id="file">
<label for="file" class="file-trigger">Click Me</label>
And you can style your "label" element
#file {
display: none;
}
.file-trigger {
/* your style */
}
As of 2022, modern browsers support file button pseudo selector. I was only struggling with Safari v16.1 which didn't work as expected and had to workaround button hiding (::-webkit-file-upload-button part).
input[type=file]::file-selector-button {
display: none;
}
input[type=file]::-webkit-file-upload-button {
display: block;
width: 0;
height: 0;
margin-left: -100%;
}
input[type=file]::-ms-browse {
display: none;
}
You may also use concise syntax:
::file-selector-button {
/* ... */
}
::-webkit-file-upload-button {
/* ... */
}
::-ms-browse {
/* ... */
}