Styling an <input type="file">
This is an old conversation and I don't know if anyone is still listening, but I believe I have a contribution to make.
I don't do anything server-side, so I have nothing to contribute there. I have tried every javascript/CSS suggestion I've run into, but without success, even the elegant but ultimately unworkable Quirksmode solution [at
http://www.quirksmode.org/dom/inputfile.html].
I believe I have a working solution for Firefox 1.5, I see no impediment to its implementation on other browsers and I would be curious to see if it indeed has generality. What's more is that this works for browsing for a file name to do local file read/write, which is what I was really looking to do.
Without going into great detail about why previous ideas did not work, here's what I found works (for Firefox 1.5):
- simulating a click of the "Browse" button didn't work (no surprise) as the .click() method is not implemented (in this and other browsers) for this element, so I opted for a manual click
- underlaying a "fake" file input (and fake Browse button) under a zero-opacity "real" one was difficult (I could never get the alignment just right), until I sized the real one to height 0px or 1px and used right-alignment to reliably overlap the "fake" and "real" Browse buttons just right;
- suggesting a file name is, as you no doubt know, impossible for "real" file inputs and easy for a "fake one", but then manually modifying the suggested name was then impossible because clicking on the visible text-box brought you into the invisible but "real" text-box of higher z-index, until I shortened the "real" text-box width to 1 (<input type=file width=1>)
- if the Browse button is used to select an existing file name, the name goes into the "real" but invisible text-box, so I implemented a setInterval that would look for a change in the value property and transfer the value of the "real" input to that of the "fake" one; the setInterval is triggered by the "real" Browse button click using the onClick event (this is where I'm curious about generality - do other browsers implement an onClick event for file inputs?)
- to then allow manual modification of the file name (in the "fake" filename field), I need to turn off the setInterval transfer hack (otherwise, the contents would be forever restored to what the "real" filename field contains), and this turn-off uses the "fake" text-box's onSelect, onClick and onChange events (all three, just in case)
- I then act on the "fake" filename
Altogether, this works like a charm.
Here's a code snippet to convey the idea:
<style>
div.UnstylableRealInput {position: relative; height: 1px; z-index: 2}
input.UnstylableRealInput {position: relative; -moz-opacity: 0; filter: alpha(opacity: 0); opacity: 0; z-index: 2; font-family: whatever; font-size: whatever}
div.StyledFakeInput {position: absolute; z-index: 1}
input.StyledFakeInput {font-family: whatever; font-size: whatever}
</style>
<div class="containerDiv" align=right>
<div class="StyledFakeInput">
<input type=text width=100 class="StyledFakeInput" onChange="clearInterval(anInterval);" onSelect="clearInterval(anInterval);" onClick="clearInterval(anInterval);" id="FakeInput">
<input type=button value="Browse">
<input type=button value="Go" onClick="doSomethingWithThisFile();">
</div>
<div class="UnstylableRealInput">
<input type=file width=1 class="UnstylableRealInput" onClick="transferInputContent();" id="RealInput">
</div>
</div>
<script language="Javascript">
var anInterval;
function transferInputContent() {
anInterval = setInterval("copyFileName();",100);
}
function copyFileName() {
if (document.getElementById('RealInput').value != document.getElementById('FakeInput').value) {
document.getElementById('FakeInput').value = document.getElementById('RealInput').value;
}
}
function doSomethingWithThisFile() {
clearInterval(anInterval);
read/write or whatever
}
</script>
An image can of course be used instead of the "fake" button.
------------------------
professional tinkerer
amateur expert
at your humble service