Search with Voice
Search field with a microphone trigger that toggles a recording state — pulses a halo while "listening". Real `<input type="search">` so AT announces it as a search field.
Search with Voice the 20th of 28 designs in the 28 CSS Input Field Designs collection. The design pairs CSS styling with a small amount of JavaScript for interactivity. Copy the HTML, CSS and JavaScript panels below into your project — the JS is self-contained, has zero dependencies, and is safe to drop into any framework (React, Vue, Svelte, plain HTML). The design honours prefers-reduced-motion and uses real semantic markup, so it ships accessibility-ready out of the box.
Live preview
The code
<form class="if-voice" role="search" autocomplete="off">
<label class="if-voice-label" for="if-voice-input">Voice search</label>
<span class="if-voice-wrap">
<svg viewBox="0 0 24 24" aria-hidden="true" class="if-voice-glass">
<circle cx="11" cy="11" r="7" />
<path d="m20 20-3.5-3.5" />
</svg>
<input
id="if-voice-input"
type="search"
name="q"
inputmode="search"
placeholder="Speak or type to search..."
/>
<button
type="button"
class="if-voice-mic"
aria-label="Start voice input"
aria-pressed="false"
data-if-voice
>
<svg viewBox="0 0 24 24" aria-hidden="true">
<rect x="9" y="3" width="6" height="11" rx="3" />
<path d="M5 11a7 7 0 0 0 14 0M12 18v3" />
</svg>
</button>
</span>
</form> .if-voice {
display: grid;
gap: 6px;
width: 100%;
max-width: 320px;
}
.if-voice-label {
font-family: "JetBrains Mono", monospace;
font-size: 10px;
letter-spacing: 0.12em;
color: #b8b6d4;
text-transform: uppercase;
}
.if-voice-wrap {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 4px 4px 4px 14px;
background: #1a1a22;
border: 1px solid rgba(255, 255, 255, 0.12);
border-radius: 10px;
transition: border-color 0.2s;
}
.if-voice-wrap:focus-within {
border-color: #ff6c8a;
}
.if-voice-glass {
width: 16px;
height: 16px;
flex-shrink: 0;
fill: none;
stroke: #6b6987;
stroke-width: 2;
stroke-linecap: round;
}
.if-voice input {
flex: 1;
min-width: 0;
padding: 8px 0;
border: 0;
outline: none;
background: transparent;
color: #f0eeff;
font:
500 14px/1 system-ui,
sans-serif;
}
.if-voice input::placeholder {
color: #b8b6d4;
}
.if-voice-mic {
width: 36px;
height: 36px;
flex-shrink: 0;
border: 0;
cursor: pointer;
background: transparent;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
position: relative;
transition: background 0.2s;
}
.if-voice-mic:hover {
background: rgba(255, 108, 138, 0.1);
}
.if-voice-mic svg {
width: 16px;
height: 16px;
fill: none;
stroke: #a78bfa;
stroke-width: 2;
stroke-linecap: round;
}
.if-voice-mic[aria-pressed="true"] svg {
stroke: #ff6c8a;
}
.if-voice-mic[aria-pressed="true"]::after {
content: "";
position: absolute;
inset: 4px;
border-radius: 6px;
border: 1.5px solid #ff6c8a;
animation: if-voice-pulse 1.2s ease-out infinite;
}
@keyframes if-voice-pulse {
0% { transform: scale(0.8); opacity: 1; }
100% { transform: scale(1.4); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
.if-voice-mic[aria-pressed="true"]::after {
animation: none !important;
}
} // Voice button — toggle aria-pressed (mock recording state for the demo)
document.querySelectorAll("[data-if-voice]").forEach(function (btn) {
btn.addEventListener("click", function () {
var on = btn.getAttribute("aria-pressed") === "true";
btn.setAttribute("aria-pressed", on ? "false" : "true");
btn.setAttribute("aria-label", on ? "Start voice input" : "Stop voice input");
// Hook real Web Speech API here if you want actual voice input:
// const rec = new (window.SpeechRecognition || window.webkitSpeechRecognition)();
});
});