Drupal Tips - How to theme the File Upload field in a WebForm using CSS and JavaScript?

| | 3 min read

The trick explained briefly

We are not actually going to theme the file upload field as it is presently nearly impossible to do that. Instead we are going to put an ordinary looking 'dummy' input text field over the file field. Next we proceed to make the 'original' file upload field invisible but accessible to the user via CSS. So when a user clicks on the dummy input text field they are actually clicking on the file upload field itself. To make it authentic we are going to copy the file path from the file upload field to the text input field via javascript.

So here are the steps to theme the file upload field in a webform.

We need to use a combination of CSS and javascript. Have a look at the javascript code. You could add the input field normally via HTML but its better to add it via javascript to get more control over the field dynamically. Here is the javascript to add the dummy input field to the real file input field and to pass the values in reverse.

function fileUploadTheming() {
  var fakeFileUpload = document.createElement('div'); //Creating the div tag for the fake input element to cover the file input
  fakeFileUpload.className = 'fakefile'; //Adding the class name to the previous div
  fakeFileUpload.appendChild(document.createElement('input')); //Adding the input element inside the previous div tag
  var x = document.getElementsByTagName('input'); //Getting all the input elements in the page and passing them to a variable
  for (var i=0;i<x.length;i++) { //We need to look for the correct. 
    if (x[i].type != 'file') continue; //Continue search till we find the file upload fields 
    x[i].className = 'file-hidden'; //We are changing the class name of the file upload field to prevent issues with browsers
    var clone = fakeFileUpload.cloneNode(true);  
    x[i].parentNode.appendChild(clone); //Adding the fake input box to the existing file input field div.
    x[i].relatedElement = clone.getElementsByTagName('input')[0];
    x[i].onchange = x[i].onmouseout = function () {
      this.relatedElement.value = this.value; //Passing the value in the real file input field to the fake one
    }
  }
}

Javascript Explained

The logic is fairly easy.The first 3 lines of code in the javascript are concerned with the creation of the fake input field. First we create a div tag, give it a class name and the add the input field to it. Next we need to find out all the input fields in the form using the getElementsByTagName() method. From the input fields we have received we need to get to the actual file upload field. Once we find the field we change its class name to file-hidden so that we can style it in CSS. Next is the important stuff. We need to place our dummy input field into the div of the original file field so that they can be positioned on top of each other. To do that we clone the node we created earlier and then append it to the the real field. As a final touch of authenticity, we need to pass the value from the original file field after the user has selected the file,to the dummy field when the value in the original field has been changed and the users mouse passes over the fake field. This is done in the last two lines of the code.

Theming the file upload using CSS

#webform-client-form-2476 .file-hidden{
  opacity: 0;
  position: relative;
  z-index: 2;
  top: 18px;
}    
#webform-client-form-2476 .fakefile input{
  width: 450px;
  height: 50px;
  margin: auto;
  background-color: #E8E8E8;
  border: 2px solid #777777;
  font-size: 15px;
  color: #787878;
  padding-left: 8px;
  position: absolute;
  z-index: 1;
  background-image: url('../images/browse_button.jpg');
  background-repeat:no-repeat;
  background-position: right;
  position: relative;
  bottom: 20px;
  right: 3px;
}

CSS Explained

The basic logic in the CSS to keep the two input fields one on top of each other while displaying only one to the user. The original file input field should be kept on top of the dummy input field but it should be hidden. To do this we should set the z-index to 2 and opacity to 0; The dummy field should come below the original file and so we set the z-index to 1. The rest of the CSS is concerned with the position of the dummy field. Set the original field position to relative and set the dummy field position to absolute. This will ensure that the dummy field is always covering the real one. The rest of CSS is just purely aesthetic to theme the file input field, which is what we wanted to do in the first place. See the theming in action at: http://www.zyxware.com/careers/job-openings/business-development-associ…

Reference - http://www.quirksmode.org/dom/inputfile.html