CSS Pseudo-element ::file-selector-button (และ ::-webkit-file-upload-button) ใช้จัดสไตล์ปุ่ม "Browse/Choose File" ของ <input type="file"> ได้โดยตรง ไม่ต้องใช้ Hack ซ่อน Input แล้วสร้างปุ่มแทน
Syntax
selector::file-selector-button {
/* Standard (Firefox) */
property: value;
}
selector::-webkit-file-upload-button {
/* WebKit/Blink (Chrome, Safari, Edge) */
property: value;
}
Browser Support
| Browser | Selector | Support |
|---|---|---|
| Firefox | ::file-selector-button | Full ✅ |
| Chrome 89+ | ::-webkit-file-upload-button | Full ✅ |
| Safari 15.4+ | ::-webkit-file-upload-button | Full ✅ |
| Edge 89+ | ::-webkit-file-upload-button | Full ✅ |
| Safari < 15.4 | - | ไม่รองรับ ❌ |
ตัวอย่างที่ 1: Firefox - Hover Effect
<!DOCTYPE html>
<html>
<head>
<style>
input[type=file]::file-selector-button:hover {
cursor: grab;
background-color: blueviolet;
color: white;
font-size: 1.2em;
box-shadow: inset 5px 10px 10px cornflowerblue;
}
</style>
</head>
<body>
<form>
<label for="fup">Click to</label>
<input type="file" id="fup" />
<input type="text" placeholder="Random Text here" />
<button type="submit">Done</button>
</form>
</body>
</html>
ตัวอย่างที่ 2: Cross-browser (Chrome + Firefox)
<!DOCTYPE html>
<html>
<head>
<style>
input[type=file]::file-selector-button:hover,
input[type=file]::-webkit-file-upload-button:hover {
cursor: pointer;
background-color: crimson;
font-size: 1.2em;
border-radius: 25%;
box-shadow: inset 5px 10px 10px cornsilk;
}
</style>
</head>
<body>
<form>
<label for="fup">Click to</label>
<input type="file" id="fup" />
<input type="text" placeholder="using webkit prefix" />
<button type="submit">Done</button>
</form>
</body>
</html>
Complete Custom File Input Style
.file-input-wrapper {
position: relative;
display: inline-block;
width: 100%;
max-width: 400px;
}
.file-input-wrapper input[type="file"] {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
opacity: 0;
cursor: pointer;
z-index: 1;
}
.file-input-wrapper .file-button {
display: inline-flex;
align-items: center;
gap: 0.5rem;
padding: 0.75rem 1.5rem;
background: #4285f4;
color: white;
border-radius: 6px;
font-size: 1rem;
font-weight: 500;
cursor: pointer;
transition: background 0.2s, box-shadow 0.2s;
border: none;
white-space: nowrap;
}
.file-input-wrapper .file-button:hover {
background: #3367d6;
box-shadow: 0 2px 8px rgba(66,133,244,0.3);
}
.file-input-wrapper .file-button:focus-visible {
outline: none;
box-shadow: 0 0 0 3px rgba(66,133,244,0.4);
}
.file-input-wrapper .file-name {
margin-top: 0.5rem;
font-size: 0.875rem;
color: #666;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* Native Button Styling (Progressive Enhancement) */
.file-input-wrapper input[type="file"]::file-selector-button,
.file-input-wrapper input[type="file"]::-webkit-file-upload-button {
margin-right: 0.5rem;
padding: 0.5rem 1rem;
background: #4285f4;
color: white;
border: none;
border-radius: 4px;
font: inherit;
cursor: pointer;
transition: background 0.2s;
}
.file-input-wrapper input[type="file"]::file-selector-button:hover,
.file-input-wrapper input[type="file"]::-webkit-file-upload-button:hover {
background: #3367d6;
}
HTML Structure
<div class="file-input-wrapper">
<input type="file" id="avatar" accept="image/*" aria-describedby="avatar-hint">
<button type="button" class="file-button" tabindex="-1">
<svg aria-hidden="true" width="20" height="20">...upload icon...</svg>
Choose File
</button>
<div class="file-name" id="avatar-hint">No file chosen</div>
</div>
Styling คุณสมบัติเพิ่มเติม
Multiple Files
input[type="file"][multiple]::file-selector-button::after {
content: " (Multiple)";
font-size: 0.8em;
}
Accept Attribute Styling
input[type="file"][accept*="image"]::file-selector-button::before {
content: "🖼️ ";
}
input[type="file"][accept*="pdf"]::file-selector-button::before {
content: "📄 ";
}
Disabled State
input[type="file"]:disabled::file-selector-button,
input[type="file"]:disabled::-webkit-file-upload-button {
opacity: 0.5;
cursor: not-allowed;
background: #ccc;
}
Fallback สำหรับ Safari เก่า / Browser ไม่รองรับ
/* Hide native button completely */
input[type="file"]::file-selector-button,
input[type="file"]::-webkit-file-upload-button {
display: none;
}
/* Custom Button Overlay (Label Trick) */
.file-input-label {
display: inline-block;
cursor: pointer;
}
.file-input-label input[type="file"] {
position: absolute;
opacity: 0;
width: 0.1px;
height: 0.1px;
}
.file-input-label .custom-button {
/* Styles here */
}
/* JS Fallback Detection */
if (!CSS.supports('selector(::file-selector-button)') &&
!CSS.supports('selector(::-webkit-file-upload-button)')) {
document.body.classList.add('no-file-selector-support');
}
Accessibility
- ใช้
<label>ผูกกับ Input (Implicit หรือ Explicit) acceptattribute ระบุประเภทไฟล์ที่ยอมรับaria-describedbyชี้ไปยัง Element แสดงชื่อไฟล์- Custom Button ต้องมี
tabindex="-1"(ไม่รับ Focus เอง Input จะรับ) - Focus Indicator ต้องชัดเจนบน Input (ซ่อนอยู่) หรือ Label