HTML Search Element: Easy Native Search Forms Guide 2026
An html search element is the browser’s native container for search: a <search> element that wraps a site’s search controls and tells assistive technology, plainly and without extra attributes, “this is where searching happens.” Before it existed, developers marked the same region with a form carrying role="search". That worked, but it was a workaround — an ARIA role bolted onto a form to say something HTML itself could not say. The <search> element says it directly, in the markup, and that directness is the whole point of the element.
This guide covers the element from the ground up: what it is and what it is not, how it replaces role="search", the controls that belong inside it, the one rule most people get wrong (search results do not go inside it), how to handle a page with two different search areas, and two complete, runnable examples — a site search form and an on-page filter — that you can copy, paste, and run. It also covers browser support honestly, including what happens in a browser old enough not to know the element at all.
Quick Takeaways
- The
<search>element defines a search landmark. Wrapping your search controls in it is the native replacement for puttingrole="search"on a form. - It is a container for search controls, not for search results. Results belong in the main content of the page, outside the
<search>element. - The exception to that rule is small: suggestions and links that are part of quick-search functionality may live inside it, because they are part of the search feature itself.
- The control inside is usually an
<input type="search">with a real<label>, inside a<form>that submits withmethod="get"— but if your search is entirely JavaScript-driven and submits nothing, neither a form nor a submit button is required. - A page may have more than one search area — a site-wide search in the header and a filter on the page, for example — but then each
<search>needs its own distinct accessible name, so a screen reader user can tell them apart. - Do not use
<search>for navigation, for a generic filter panel that is not search, or as a wrapper for a whole page section. If it is not search, it is not<search>. - Support is settled: the element is Baseline Widely Available since October 2023 (Chrome 118, Firefox 118, Safari 17, Edge 118). In an older browser it simply behaves like an ordinary container, so using it does not break the page.
What the HTML Search Element Actually Is
Every page has regions a visitor needs to find quickly: the header, the navigation, the main content, the footer. HTML gives most of those regions their own elements — <header>, <nav>, <main>, <footer> — and screen readers turn those elements into landmarks, a kind of table of contents for the page that a keyboard or screen reader user can jump between. For years, search was the odd one out. There was no element for it. The only way to mark a search region as a landmark was to add role="search" to a form, borrowing a role from ARIA because HTML had nothing to offer.
The <search> element, added to the HTML specification in 2023, closes that gap. It is a container element whose entire job is to represent the parts of a page that provide search or filtering functionality. Its implicit ARIA role is search, which means a browser that understands the element exposes it as a search landmark automatically. No role attribute, no extra markup, no JavaScript — the landmark comes free with the element itself.
That last point is worth pausing on, because it explains why the element exists at all. The web platform has a standing principle: if a pattern is common enough, give it a native element instead of making everyone fake it with roles and classes. Search is one of the most common patterns on the web — nearly every site of any size has a search box — and it was still being faked. The <search> element is the platform catching up with what developers were already doing, and giving that pattern a name browsers and assistive technology can recognise without help.
1. The old way: role=search on a form
Before <search>, the standard pattern looked like this:
<form role="search" action="/search" method="get">
<label for="site-search">Search the site</label>
<input type="search" id="site-search" name="q">
<button type="submit">Search</button>
</form>
There is nothing wrong with this code, and it still works. The role="search" attribute is what turns the form into a search landmark, and screen readers announce it as one. If you have this pattern in an old codebase, you do not need to rush to replace it — it is valid, it is understood, and removing it gains you nothing urgent.
But notice what the role is doing: it is compensating for a missing element. The form is doing two jobs at once — submitting the query, and announcing itself as the search region. When the element exists, those jobs separate cleanly. The <search> element announces the region; the form inside it submits the query. Each piece of markup does one job, and the markup reads the way the page actually works.
2. The new way: search wraps the form
The same search, written with the element, looks like this:
<search>
<form action="/search" method="get">
<label for="site-search">Search the site</label>
<input type="search" id="site-search" name="q">
<button type="submit">Search</button>
</form>
</search>
The difference is one element and one removed attribute. The <search> wrapper provides the landmark, so the form no longer needs role="search". Everything else — the label, the input, the submit button, the GET submission — stays exactly the same. That is deliberate: the element changes how the region is announced, not how search works. Your server still receives the same query, your CSS still styles the same controls, and your JavaScript still listens to the same submit event.
One practical consequence follows from the separation. Because the landmark now lives on the wrapper, the search feature can contain more than a form. A search area often includes extra controls — a scope selector, an “exact matches only” checkbox, a set of quick links — and all of those belong inside the same <search> element, because they are all part of the search feature. Under the old pattern, those extras sat awkwardly outside the landmark form or inside it without a clear reason. Under the new pattern, the wrapper holds the whole feature, and the form holds only what gets submitted.
3. What the element does not do
The <search> element adds semantics, not behaviour. It does not search anything by itself, it does not style anything by itself, and it does not change how a form submits. If you wrap a search box in <search> and change nothing else, the page looks identical and behaves identically for sighted mouse users. The change is visible to assistive technology and to anyone reading the markup — which is exactly the audience semantic HTML is for.
That also means the element is not a search engine optimisation trick. It will not lift a page in Google’s rankings, and any article claiming otherwise is selling something. What it does is make the page’s structure honest: the search region is labelled as a search region in the language browsers understand, rather than implied by a class name or a placeholder. Accessibility and maintainability are the return on this element, not rankings, and a guide that promised otherwise would be dishonest about what semantic HTML can do.
The Controls Inside: Input, Label, Button, Form
A landmark with nothing in it helps nobody. The value of the <search> element comes from the controls it wraps, and those controls have their own rules. Most search bugs are not landmark bugs — they are label bugs, submission bugs, or input-type bugs that the landmark cannot fix. Get the controls right first, and the wrapper does its job on top of them.
1. Use input type=search, not type=text
The input inside a search feature should be <input type="search">, not <input type="text">. The two look similar, but they are not the same control. A search input tells the browser the field’s purpose is entering a search query, and browsers are allowed to treat it accordingly — some show a clear control inside the field, and mobile keyboards may adjust. More importantly, it tells assistive technology and anyone reading the markup that this field is for searching, which a generic text field does not say.
The distinction mirrors the element itself: just as <search> replaced a generic container plus a role, type="search" replaces a generic text field plus an assumption. In both cases the native form says what the generic form only implied. Use both together — a search input inside a search element — and the whole feature is described natively, from the landmark down to the field.
2. Every input needs a real label
A placeholder is not a label. This is one of the most repeated rules in form accessibility, and search boxes break it more than any other control, because a search box often shows a grey “Search…” hint and nothing else. A placeholder disappears the moment the visitor types, it is not reliably announced as the field’s name, and it leaves a screen reader user guessing what the field is for once they have started typing.
The fix is one line:
<label for="site-search">Search the site</label>
<input type="search" id="site-search" name="q">
If the design genuinely has no room for a visible label, hide it visually while keeping it in the accessibility tree — the standard visually-hidden class pattern — rather than deleting it. The label’s text should also say what is being searched: “Search the site” for a site search, “Filter articles” for a page filter, “Search products” for a shop. A label that just says “Search” is acceptable for a single site search, but the moment a page has two search areas, the vague label becomes a real problem, covered in the next section.
3. The form: GET, an action, and a name
When a search submits to a server, the form should use method="get" and an action pointing at the results page, and the input should carry a name attribute. GET matters because a search is a safe, repeatable request: the query ends up in the URL, which means the results page is bookmarkable, shareable, and reachable with the back button. A search submitted with POST hides the query, breaks the back button’s expectations, and warns on refresh — all for a request that changes nothing on the server.
<search>
<form action="/search" method="get">
<label for="site-search">Search the site</label>
<input type="search" id="site-search" name="q">
<button type="submit">Search</button>
</form>
</search>
The name="q" attribute is what turns the typed text into a query parameter: submitting “headings” sends the browser to /search?q=headings. Without a name, the input’s value is not submitted at all, and the search silently returns nothing — a bug that looks like a broken search feature but is really a missing attribute. If your search form ever submits and the results page acts as if nothing was typed, check the name attribute first.
4. When there is no form at all
Not every search submits to a server. An on-page filter — typing to narrow a list already on the page — is search functionality implemented entirely in JavaScript, and in that case neither a form nor a submit button is required. MDN is explicit on this point: when no form is submitted, the <search> element still belongs, containing the search and filtering capabilities on its own.
<search>
<label for="article-filter">Filter articles</label>
<input type="search" id="article-filter">
</search>
The filter example later in this guide uses exactly this shape. The rule of thumb is simple: if pressing Enter should load a results page, you need a form; if typing should narrow what is already visible, you do not. What you always need, in both cases, is the <search> wrapper and a label — those are about meaning, not about submission.
Two Search Areas on One Page: Give Each a Name
A single search landmark needs no name. A screen reader announcing “search landmark” on a page with one search area is unambiguous. But many real pages have two: a site-wide search in the header, and a filter for the content on the page itself — a shop’s product filter, a documentation site’s page filter, a blog’s archive filter. Two landmarks both announced as “search” are indistinguishable, and a visitor navigating by landmarks cannot tell which is which.
The fix is to give each <search> element its own distinct accessible name with aria-label:
<header>
<search aria-label="Site search">
<form action="/search" method="get">
<label for="site-search">Search the site</label>
<input type="search" id="site-search" name="q">
<button type="submit">Search</button>
</form>
</search>
</header>
<main>
<search aria-label="Filter articles">
<label for="article-filter">Filter articles</label>
<input type="search" id="article-filter">
</search>
<!-- articles list lives here, in main content, NOT inside search -->
</main>
Now the landmarks announce as “Site search” and “Filter articles”, and navigating between them is a choice, not a guess. MDN’s own two-search example makes the same point with the title attribute on each <search> element; aria-label is the more direct and more widely supported way to name a landmark, and it is the one to reach for here. Whichever mechanism you use, the requirement is the same: distinct names for distinct search areas, describing what each one searches.
This is also where the label rule from the previous section earns its keep. “Search the site” and “Filter articles” are not just labels for sighted users — they are the visible text that matches the landmark names, so the page is consistent for everyone. A page whose header search is labelled “Search” and whose filter is also labelled “Search” has failed twice: once at the landmark level, once at the field level. Name things by what they search, and both levels fix themselves.
One more naming caution: do not give a single search area a name it does not need in a way that confuses. A lone site search wrapped in <search> with no aria-label announces perfectly well as a search landmark. Adding aria-label="Search" to it adds nothing. Save accessible names for the case that needs them — multiple search landmarks — and keep the single case simple.
The Rule Most People Get Wrong: Results Do Not Go Inside
If this guide had only one rule to drill in, it would be this one: the <search> element is not for presenting search results. Search or filtered results should be presented as part of the main content of the page, outside the <search> element. This is stated plainly in MDN’s reference, and it is the mistake that shows up most often in real code — a results list tucked inside the search wrapper because the developer thought of “the search feature” as one big block containing everything search-related.
Why does the boundary matter? Because the landmark’s job is to identify the controls, not the outcome. A screen reader user jumping to the search landmark expects to find the search box and its controls, ready to type. If the landmark also contains fifty results, that user has to wade through the results to get back to the controls, and the landmark has stopped being a shortcut and become an obstacle. Keeping results in main content keeps the landmark small, predictable, and useful: controls in the landmark, results in the content, each where the visitor expects them.
<!-- Wrong: results inside search -->
<search>
<form action="/search" method="get">
<label for="site-search">Search the site</label>
<input type="search" id="site-search" name="q">
<button type="submit">Search</button>
</form>
<ul>
<li>Result one</li>
<li>Result two</li>
</ul>
</search>
<!-- Right: controls in search, results in main content -->
<search>
<form action="/search" method="get">
<label for="site-search">Search the site</label>
<input type="search" id="site-search" name="q">
<button type="submit">Search</button>
</form>
</search>
<main>
<ul>
<li>Result one</li>
<li>Result two</li>
</ul>
</main>
1. The one exception: quick-search suggestions
There is a narrow exception, and it is worth stating precisely because it is easy to over-read. Suggestions and links that are part of quick-search functionality — the dropdown that appears as you type, offering completions or popular searches — are appropriately nested within the <search> element, because they are part of the search feature itself, not its results. A suggestion dropdown is a control: it helps the visitor complete a query. A results list is content: it answers a query already made. That distinction — controls versus content — is the test to apply whenever you are unsure whether something belongs inside.
The same test resolves the filter case. In a JavaScript filter, the list being filtered is content, so it stays outside. The input and any filter toggles are controls, so they stay inside. MDN’s filter example follows exactly this shape: the <search> element holds the input and a checkbox, while the results section sits alongside it, not within it. When in doubt, ask whether the thing in question helps the visitor search, or shows them what searching found. Helpers go inside; findings go outside.
2. What is not search at all
The element’s name invites overuse, and overuse is the second common mistake. Do not wrap a navigation menu in <search> because it “helps people find things” — that is what <nav> is for. Do not wrap a sorting control or a category filter that has nothing to do with searching — if no query is being entered and nothing is being searched or filtered by text, the element does not apply. And do not wrap an entire page section in <search> just because it contains a search box somewhere inside it; the element should wrap the search feature, not the neighbourhood it lives in.
A useful smell test: if you removed the search box from the wrapper, would anything meaningful remain? If the wrapper would be empty or would contain unrelated content, the wrapper is too big. Tighten it until it contains the search controls and nothing else, and the landmark will mean what it says.
Browser Support and the Old-Browser Story
Support for the <search> element is settled, and that is a genuine change from a few years ago. The element is Baseline Widely Available since October 2023, with Chrome 118, Firefox 118, Safari 17, and Edge 118 all shipping it. For a site in 2026, that means the overwhelming majority of visitors get the real landmark, and the element can be used in production without a feature check or a polyfill.
The old-browser story is equally reassuring, and it is the reason no fallback is required. HTML has a forgiving rule for unknown elements: a browser that does not recognise a tag treats it as an ordinary generic container. It still renders, it still holds its children, and the form inside it still submits. What is lost in such a browser is only the landmark announcement — the search still works, it is just not announced as a landmark. That is a graceful degradation, not a breakage: functionality intact, semantics absent, and only for visitors on browsers several years out of date.
There is one practical consequence worth noting. Because an unknown <search> element behaves like a generic container, it has no default styling of its own — but neither does the known element. <search> carries no built-in margins, padding, or layout, in any browser. It is a semantic wrapper, and your CSS is responsible for how the search feature looks, exactly as it would be for a <div> wrapper. If your search feature looks unstyled after switching to <search>, that is not the element failing; it is the element doing exactly what a semantic wrapper does, which is nothing visual at all.
Common Mistakes Checklist
Before the examples, a short checklist of the mistakes this guide has covered, in the order you are most likely to make them:
- Results inside the landmark. The results list belongs in main content. Only quick-search suggestions belong inside, because they are controls, not results.
- A placeholder instead of a label. The grey hint text is not a name. Give every search input a
<label>, visible or visually hidden, that says what is being searched. - Two search landmarks with no names. One search area needs no name; two need distinct
aria-labelvalues, or a landmark user cannot tell them apart. - A text input instead of a search input.
type="text"works, but it does not say the field is for searching. Usetype="search"and let the control describe itself. - A missing name attribute. A form input without a
namesubmits nothing. If a search form returns empty results no matter what is typed, check this first. - POST for a search. A search is a safe, repeatable request. Use GET so the results page is bookmarkable and shareable.
- Wrapping non-search content. Navigation, unrelated filters, and whole sections are not search. If it is not search, it is not
<search>. - Expecting a ranking boost. The element improves accessibility and markup honesty. It is not an SEO technique, and promising otherwise would be dishonest.
Complete Working Example 1: A Site Search Form
This is a complete, runnable HTML document: a page header containing a site search, and a main area where results would appear. Copy it into a file, open it in a browser, and it works as far as a static file can — the form submits a GET request to /search?q=..., which a real site would answer with results. Notice the boundary the guide has been insisting on: the <search> element holds only the form, and the <main> element holds the results area, outside it.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Site search example</title>
<style>
body { font-family: system-ui, sans-serif; margin: 2rem; }
header { margin-bottom: 2rem; }
label { display: block; margin-bottom: 0.25rem; }
input[type="search"] { padding: 0.5rem; width: 20rem; }
button { padding: 0.5rem 1rem; }
</style>
</head>
<body>
<header>
<h1>Example Site</h1>
<search>
<form action="/search" method="get">
<label for="site-search">Search the site</label>
<input type="search" id="site-search" name="q">
<button type="submit">Search</button>
</form>
</search>
</header>
<main>
<h2>Results</h2>
<p>Results for the submitted query would appear here, in main content — never inside the search element.</p>
</main>
</body>
</html>
Three details in this example deserve a second look. First, the form’s method="get" puts the query in the URL, so a results page for “headings” lives at /search?q=headings and can be linked to directly. Second, the input’s name="q" is what makes that parameter exist at all. Third, the results heading and paragraph sit in <main>, demonstrating the boundary in code rather than just describing it: controls in the landmark, content in the main region.
Complete Working Example 2: An On-Page Filter
This is a complete, runnable HTML document with no server involved: typing in the filter narrows a list of articles already on the page. There is no form and no submit button, because nothing is submitted — the search is entirely JavaScript-driven, and MDN’s guidance for that case is followed exactly. The list is fully visible before any typing, so the page also works with JavaScript disabled: a visitor without JavaScript simply sees the whole list, which is the correct fallback for a filter.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Article filter example</title>
<style>
body { font-family: system-ui, sans-serif; margin: 2rem; }
label { display: block; margin-bottom: 0.25rem; }
input[type="search"] { padding: 0.5rem; width: 20rem; }
</style>
</head>
<body>
<main>
<h1>Articles</h1>
<search aria-label="Filter articles">
<label for="article-filter">Filter articles</label>
<input type="search" id="article-filter">
</search>
<ul id="article-list">
<li>HTML Headings Hierarchy</li>
<li>Responsive Images in HTML</li>
<li>HTML Dialog Element</li>
<li>JavaScript Popover</li>
<li>HTML Search Element</li>
</ul>
<p id="no-results" hidden>No articles match your filter.</p>
</main>
<script>
const filter = document.querySelector("#article-filter");
const items = document.querySelectorAll("#article-list li");
const empty = document.querySelector("#no-results");
filter.addEventListener("input", () => {
const query = filter.value.trim().toLowerCase();
let visible = 0;
items.forEach((item) => {
const match = item.textContent.toLowerCase().includes(query);
item.hidden = !match;
if (match) visible += 1;
});
empty.hidden = visible > 0;
});
</script>
</body>
</html>
The script is deliberately small, and each part maps to a rule from this guide. The <search> element carries aria-label="Filter articles" because this page, in a real site, would sit alongside a header site search — the example names its landmark for the two-search case even though only one search appears in the file, so the pattern copies correctly into a real header. The list itself is outside <search>, in main content, as the results rule requires. And the filtering is case-insensitive and trims whitespace, so ” dialog ” still finds the dialog article — a small kindness that costs one line and saves real visitors real confusion.
Frequently Asked Questions
1. Is the html search element just a div with role=search?
No, and the difference is the point. A <div role="search"> is a generic container borrowing a landmark role from ARIA; a <search> element is a native element whose implicit role is search. Both announce as a search landmark in a modern browser, but the native element says what it is in the markup itself, needs no role attribute, and is understood by any tool that reads HTML semantics rather than ARIA roles. The div version still works and does not need urgent replacement, but for new code the element is the right choice.
2. Should search results go inside the search element?
No. Search or filtered results belong in the main content of the page, outside the <search> element. The element wraps the search controls — the input, the form, the filter toggles, and quick-search suggestions. Putting results inside makes the landmark contain content instead of controls, and forces a landmark user to wade through results to reach the search box again. Keep the boundary: controls inside, results outside.
3. Can a page have more than one search element?
Yes. A common pattern is a site-wide search in the header plus a filter for the page’s own content. When a page has more than one <search> element, give each one a distinct accessible name with aria-label — for example “Site search” and “Filter articles” — so a screen reader user navigating by landmarks can tell them apart. A page with a single search area needs no name at all.
4. Does the search element replace the form element?
No. The <search> element wraps the form; it does not replace it. When a search submits to a server, you still need a <form> with an action, a GET method, and a named input, and a submit button. The element provides the landmark; the form provides the submission. The only case with no form is a search implemented entirely in JavaScript, such as an on-page filter, where nothing is submitted at all.
5. What happens in a browser that does not support the search element?
Nothing breaks. A browser that does not recognise the element treats it as an ordinary generic container: the page renders, the form inside it still submits, and the filter inside it still filters. The only loss is the landmark announcement, and only for visitors on browsers older than the October 2023 Baseline (Chrome 118, Firefox 118, Safari 17, Edge 118). No polyfill or fallback markup is required.
6. Will using the search element improve my Google rankings?
Not directly, and any guide promising otherwise should not be trusted. The element improves accessibility — a search landmark that assistive technology can find and announce — and it makes markup honest and maintainable. Those are real benefits, and they are the reason to use it. Search rankings depend on content, relevance, and hundreds of other signals; a semantic wrapper is not among the levers that move them, and treating it as one misunderstands what semantic HTML is for.
Conclusion
The html search element is a small addition with a clear job: give search a native home in the markup, so that the most common feature on the web no longer has to borrow a role to be recognised. Wrap your search controls in it, label the input with what it searches, submit server searches with GET and a named input, keep results in main content, and name each landmark when a page has more than one search area. That is the whole discipline, and it fits in a handful of lines.
The two examples in this guide are the place to start: the site search form for a search that loads a results page, and the on-page filter for a search that narrows what is already visible. Copy one, adapt its labels to what your site actually searches, and the feature will be described natively from the landmark down to the field — no roles, no workarounds, and no breakage in older browsers. If you have been writing role="search" on forms for years, nothing about your old code has become wrong; but for the next search box you build, the element exists, and it is the better way to say what you have always meant.