Repository navigation
feat(search,app-bar): align md-search and search app bar with Material 3 specs - #155
Conversation
There was a problem hiding this comment.
📋 Review Summary
This pull request refactors and enhances <md-search> into a dedicated, standalone Material Design 3 Search Bar component, eliminating its prior dependency on wrapping <md-text-field>. Concurrently, <md-app-bar> is updated to embed the new <md-search> element for the search variant, supporting center-aligned search styling, dynamic slotted icon detection, and custom theme tokens. The component is also exported in all.js, with accompanying updates to documentation and demo files.
🔍 General Feedback
- Refactoring
<md-search>to be an independent custom element rather than wrapping<md-text-field>significantly cleans up the DOM structure, avoids nested shadow DOM styling conflicts, and closely aligns with the official Material 3 Search Bar specification. - Exporting
Searchfromall.jsresolves an omission in the bundle exports, ensuring consumers using the top-level bundle can import the search component seamlessly. - Documentation in
app/README.mdandsearch/README.mdis updated thoroughly with accurate token definitions and event tables.
📊 Token Usage & Cost Efficiency
| Metric | Value |
|---|---|
| Input Tokens (uncached) | 46,629 |
| Input Tokens (cached) | 431,576 (⚡ 90.2% cached) |
| Thinking / Reasoning Tokens | 240 |
| Output Tokens | 709 |
| Total Session Tokens | 479,154 |
| Cost (uncached input) | $0.0350 |
| Cost (cached input) | $0.0324 |
| Cost (thinking / reasoning) | $0.0009 |
| Cost (response output) | $0.0027 |
| Estimated Total Cost | $0.0709 |
Gemini 3.8 Flash: introductory rate $0.75/$3.75 per 1M applied; reverts to $1.5/$7.5 after 2026-12-31.
Gemini 3.8 Flash: standard tier; batch and flex are half again, priority is higher.
Cache reads are priced here, but context-cache STORAGE, where the model charges for it separately per token-hour, is not included, so the figure can run slightly low.
There was a problem hiding this comment.
📋 Review Summary
This pull request integrates the newly rewritten <md-search> component into <md-app-bar>'s search variant, replacing the previous plain <md-text-field> implementation with an authentic Material 3 Search Bar. It exposes <md-search> via all.js, expands documentation across both component directories, and adds slot-detection to dynamically hide unused navigation and action containers in the top app bar. Overall, the architectural integration is clean, highly compliant with Material Design 3 specifications, and enhances visual fidelity across desktop and mobile form factors.
✅ Resolved Items from Prior Reviews
- Re-dispatched the native 'change' event from in _handleSearchChange so change events cross the shadow DOM boundary. (
app/bar.js:234) - Ensured event consistency in by dispatching an InputEvent with bubbles: true and composed: true upon clear(), matching user input semantics. (
search/search.js:116)
🔍 General Feedback
- The transition of
<md-app-bar type="search">from a generic<md-text-field>to a dedicated<md-search>component aligns much more closely with the Material 3 Search specification, providing proper 56px pill container styling, interactive state layers, and clear button orchestration. - Updating the variant evaluation order in
_effectiveTypeso thattype="search"is prioritised abovecenterAlignedcleanly resolves variant collision while allowingcenter-alignedto pass through as an alignment preference to<md-search>. - The inclusion of slot-state tracking (
_hasLeadingand_hasTrailing) eliminates the awkward 48px indentation in standard small app bars when no navigation or trailing icons are provided. - 💡 Additional Feedback on Unmodified Lines:
- app/bar.js (Line 110): 🟡
_handleLeadingSlotChange()and_handleTrailingSlotChange()currently depend solely on@slotchangeevents. If the custom element is upgraded after light DOM nodes have already been parsed into the DOM, or during SSR hydration,@slotchangemay not fire on initial connection. This leaves_hasLeadingand_hasTrailingasfalseon the initial paint, causing a flash of unstyled content (FOUC). Adding afirstUpdated()lifecycle hook ensures the initial slotted nodes are evaluated immediately.firstUpdated(changedProperties) { super.firstUpdated?.(changedProperties) this._handleLeadingSlotChange() this._handleTrailingSlotChange() const subtitleSlot = this.renderRoot?.querySelector('slot[name="subtitle"]') if (subtitleSlot) { this._hasSlottedSubtitle = this._hasAssignedContent(subtitleSlot) } } updated(changedProperties) { super.updated(changedProperties) if (changedProperties.has('scrollBehavior') || changedProperties.has('scrollTarget')) { this._detachScrollListener() this._attachScrollListener() } if (changedProperties.has('value')) { this._hasSearchValue = Boolean(this.value) } }
📊 Token Usage & Cost Efficiency
| Metric | Value |
|---|---|
| Input Tokens (uncached) | 46,738 |
| Input Tokens (cached) | 431,576 (⚡ 90.1% cached) |
| PR Comments History Tokens | 549 |
| Thinking / Reasoning Tokens | 31,768 |
| Output Tokens | 1,530 |
| Total Session Tokens | 512,161 |
| Cost (uncached input) | $0.0355 |
| Cost (cached input) | $0.0324 |
| Cost (thinking / reasoning) | $0.1191 |
| Cost (response output) | $0.0057 |
| Estimated Total Cost | $0.1927 |
Gemini 3.8 Flash: introductory rate $0.75/$3.75 per 1M applied; reverts to $1.5/$7.5 after 2026-12-31.
Gemini 3.8 Flash: standard tier; batch and flex are half again, priority is higher.
Cache reads are priced here, but context-cache STORAGE, where the model charges for it separately per token-hour, is not included, so the figure can run slightly low.
There was a problem hiding this comment.
📋 Review Summary
This pull request promotes <md-search> into a fully-featured, standalone Material 3 search bar component and integrates it into <md-app-bar type="search"> and all.js. The search bar now accurately reflects the Material 3 Search specification, providing resting/scrolled container color styling, elevation, clear actions, leading/trailing slots, and avatar support. Overall implementation quality is high, with excellent documentation and comprehensive demo updates.
✅ Resolved Items from Prior Reviews
- Added redispatchEvent(this, e) to _handleSearchChange in AppBar so change events cross the shadow boundary to external consumers. (
app/bar.js:234) - Standardised event dispatching in Search._clear() to use InputEvent with bubbles: true and composed: true matching native input events. (
search/search.js:116)
🔍 General Feedback
- The new standalone
<md-search>implementation is well architected, replacing the previous minimal<md-text-field>wrapper with a dedicated Material 3 search container featuring state layers, elevation, and flexible slotting. - Updating
<md-app-bar type="search">to use<md-search>provides a cohesive search experience and seamless slot forwarding for leading/trailing actions. - Documentation in both
app/README.mdandsearch/README.mdhas been thoroughly updated with accurate property tables, slots, events, and CSS tokens.
📊 Token Usage & Cost Efficiency
| Metric | Value |
|---|---|
| Input Tokens (uncached) | 47,656 |
| Input Tokens (cached) | 431,576 (⚡ 90.0% cached) |
| PR Comments History Tokens | 549 |
| Thinking / Reasoning Tokens | 17,507 |
| Output Tokens | 853 |
| Total Session Tokens | 498,141 |
| Cost (uncached input) | $0.0362 |
| Cost (cached input) | $0.0324 |
| Cost (thinking / reasoning) | $0.0657 |
| Cost (response output) | $0.0032 |
| Estimated Total Cost | $0.1374 |
Gemini 3.8 Flash: introductory rate $0.75/$3.75 per 1M applied; reverts to $1.5/$7.5 after 2026-12-31.
Gemini 3.8 Flash: standard tier; batch and flex are half again, priority is higher.
Cache reads are priced here, but context-cache STORAGE, where the model charges for it separately per token-hour, is not included, so the figure can run slightly low.
…rm button type, and center-aligned spacing
🚀 Deploying Preview to Cloudflare 🚀Preview URL: https://verify-search-bar-spec-material.treeder.workers.dev (commit 3e0092f)This URL reflects your latest Preview deploymentPreview Deployments by commit
|
There was a problem hiding this comment.
📋 Review Summary
This pull request completes the transition of <md-search> into a standalone, fully-featured Material 3 Search Bar component and integrates it into <md-app-bar>'s search variant. It also exports the search module in all.js, bumps the package version to 3.5.0, and expands documentation and demo pages. All review feedback from previous iterations—including slot hydration checks, event redispatching, dead code removal, and center-aligned layout symmetry—has been properly addressed.
✅ Resolved Items from Prior Reviews
- Re-dispatched change event in md-app-bar so change events cross the shadow DOM boundary. (
app/bar.js:234) - Removed orphaned _clearSearch() dead code in app/bar.js. (
app/bar.js:251) - Preserved 48px footprint with visibility: hidden on center-aligned app bars when leading or trailing items are hidden to ensure headline centering remains symmetric. (
app/bar.js:519) - Set cancelable: true on the search CustomEvent in search/search.js. (
search/search.js:133) - Implemented initial slot inspection in firstUpdated() for trailing-icon and avatar slots in search/search.js. (
search/search.js:150) - Added explicit type="button" to the clear md-icon-button in search/search.js to prevent unintended form submissions. (
search/search.js:233)
🔍 General Feedback
- The rewritten
<md-search>component adheres closely to the Material 3 Search Bar specification, featuring smooth elevation, active/hover state layers, standard M3 typography tokens, and responsive slot layout. - Exporting
<md-search>viaall.jsensures convenience bundle consistency with other top-level Material 3 components in the library. - Comprehensive documentation additions in both
app/README.mdandsearch/README.mdprovide clear guidance on styling custom properties, slots, and events.
📊 Token Usage & Cost Efficiency
| Metric | Value |
|---|---|
| Input Tokens (uncached) | 48,500 |
| Input Tokens (cached) | 431,576 (⚡ 89.6% cached) |
| PR Comments History Tokens | 1,728 |
| Thinking / Reasoning Tokens | 21,421 |
| Output Tokens | 924 |
| Total Session Tokens | 504,149 |
| Cost (uncached input) | $0.0377 |
| Cost (cached input) | $0.0324 |
| Cost (thinking / reasoning) | $0.0803 |
| Cost (response output) | $0.0035 |
| Estimated Total Cost | $0.1538 |
Gemini 3.8 Flash: introductory rate $0.75/$3.75 per 1M applied; reverts to $1.5/$7.5 after 2026-12-31.
Gemini 3.8 Flash: standard tier; batch and flex are half again, priority is higher.
Cache reads are priced here, but context-cache STORAGE, where the model charges for it separately per token-hour, is not included, so the figure can run slightly low.
There was a problem hiding this comment.
📋 Review Summary
This pull request completes the transition of <md-search> into a standalone Material Design 3 Search Bar component and integrates it into <md-app-bar>'s search variant. It introduces form association, avatar/trailing slot support, clear controls, and comprehensive documentation while addressing all prior feedback.
✅ Resolved Items from Prior Reviews
- Added
redispatchEvent(this, e)to_handleSearchChangein<md-app-bar>so thatchangeevents cross the component's shadow boundary. (app/bar.js:234) - Standardised
_clear()in<md-search>to dispatchInputEvent('input', { bubbles: true, composed: true })andEvent('change', { bubbles: true }). (search/search.js:126) - Retained a 48px footprint with
visibility: hidden; display: flex;for hidden leading/trailing elements in center-aligned app bars to ensure the title remains centred. (app/bar.js:519) - Added slot checks in
firstUpdated()for<md-search>and<md-app-bar>to handle initially slotted content during SSR hydration or deferred upgrades. (search/search.js:160) - Explicitly set
type="button"on the clear<md-icon-button>inside<md-search>to prevent unintended form submission when nested in a<form>. (search/search.js:243) - Set
cancelable: trueon thesearchCustomEvent in<md-search>to allow consumers to cancel default handling. (search/search.js:143) - Removed unused/orphaned
_clearSearch()method fromapp/bar.js. (app/bar.js:251) - Implemented
mixinFormAssociatedandmixinElementInternalson<md-search>with[getFormValue](),formResetCallback(), andformStateRestoreCallback(). (search/search.js:39) - Added
outline: none;to:hostin<md-search>to suppress browser user-agent focus outlines whendelegatesFocus: trueis active. (search/search.js:258)
🔍 General Feedback
- The standalone
<md-search>component adheres closely to the Material Design 3 Search Bar specification, including the 56px height, rounded full container, state layers, elevation, and optional avatar integration. - The integration with
<md-app-bar type="search">is clean and maintains proper event bubbling and state synchronization. - Documentation updates in both
app/README.mdandsearch/README.mdare thorough and clearly describe all properties, slots, events, and CSS custom property tokens.
📊 Token Usage & Cost Efficiency
| Metric | Value |
|---|---|
| Input Tokens (uncached) | 48,787 |
| Input Tokens (cached) | 431,576 (⚡ 89.4% cached) |
| PR Comments History Tokens | 2,556 |
| Thinking / Reasoning Tokens | 11,460 |
| Output Tokens | 824 |
| Total Session Tokens | 495,203 |
| Cost (uncached input) | $0.0385 |
| Cost (cached input) | $0.0324 |
| Cost (thinking / reasoning) | $0.0430 |
| Cost (response output) | $0.0031 |
| Estimated Total Cost | $0.1169 |
Gemini 3.8 Flash: introductory rate $0.75/$3.75 per 1M applied; reverts to $1.5/$7.5 after 2026-12-31.
Gemini 3.8 Flash: standard tier; batch and flex are half again, priority is higher.
Cache reads are priced here, but context-cache STORAGE, where the model charges for it separately per token-hour, is not included, so the figure can run slightly low.
There was a problem hiding this comment.
📋 Review Summary
This pull request completes the Material Design 3 Search Bar and Search View implementation (<md-search>), integrates it cleanly into <md-app-bar>'s search variant, and updates the documentation and demo pages. Previous review feedback—including form association, event re-dispatching, symmetrical centering, and dead code removal—has been thoroughly addressed.
✅ Resolved Items from Prior Reviews
- Form association added to
<md-search>viamixinFormAssociatedandmixinElementInternals. (search/search.js:39) - Re-dispatched
changeevent from<md-app-bar>when inner<md-search>value changes. (app/bar.js:234) - Retained 48px symmetrical footprint for center-aligned top app bars when actions or navigation slots are empty. (
app/bar.js:518) - Cleaned up orphaned
_clearSearch()helper in<md-app-bar>. (app/bar.js:251) - Added explicit
type="button"to the clear icon button to avoid accidental form submission. (search/search.js:215) - Added
outline: none;on:hostto prevent duplicate browser focus outlines underdelegatesFocus: true. (search/search.js:394) - Added
firstUpdatedslot checks and ensuredcancelable: trueonsearchcustom event. (search/search.js:224)
🔍 General Feedback
- The implementation of
<md-search>aligns closely with the Material Design 3 Search Bar and Search View specification, providing clean responsive transitions between docked and full-screen modes. - Form association via
ElementInternalsandmixinFormAssociatedallows seamless participation in native<form>elements and FormData extraction. - The integration with
<md-app-bar type="search">makes excellent use of slot forwarding for icons and search suggestions.
📊 Token Usage & Cost Efficiency
| Metric | Value |
|---|---|
| Input Tokens (uncached) | 67,097 |
| Input Tokens (cached) | 427,723 (⚡ 85.9% cached) |
| PR Comments History Tokens | 2,847 |
| Thinking / Reasoning Tokens | 264 |
| Output Tokens | 595 |
| Total Session Tokens | 498,526 |
| Cost (uncached input) | $0.0525 |
| Cost (cached input) | $0.0321 |
| Cost (thinking / reasoning) | $0.0010 |
| Cost (response output) | $0.0022 |
| Estimated Total Cost | $0.0878 |
Gemini 3.8 Flash: introductory rate $0.75/$3.75 per 1M applied; reverts to $1.5/$7.5 after 2026-12-31.
Gemini 3.8 Flash: standard tier; batch and flex are half again, priority is higher.
Cache reads are priced here, but context-cache STORAGE, where the model charges for it separately per token-hour, is not included, so the figure can run slightly low.
There was a problem hiding this comment.
📋 Review Summary
This pull request completes the comprehensive implementation of the Material Design 3 Search component (), integrating it into the top app bar () and demo applications. The search component supports docked vertical-menu suggestions on wider viewports, full-screen adaptive search on compact screens, form association, clear actions, and custom avatar/trailing slots. The implementation adheres closely to the M3 Search specification and all previously raised feedback items have been addressed.
✅ Resolved Items from Prior Reviews
- Re-dispatched the change event from in _handleSearchChange so change events cross the shadow boundary. (
app/bar.js:234) - Aligned input and change event dispatch semantics across user typing and programmatic clear() invocation. (
search/search.js:208) - Retained a symmetric 48px footprint with visibility: hidden; display: flex; on hidden leading/trailing slots in center-aligned app bars to prevent headline shift. (
app/bar.js:518) - Added firstUpdated() slot checks in search/search.js and app/bar.js to properly identify slotted icons during SSR hydration and initial render. (
search/search.js:373) - Added type="button" to the clear icon button to prevent accidental form submissions when embedded in HTML forms. (
search/search.js:215) - Configured the custom search event with cancelable: true. (
search/search.js:244) - Removed orphaned _clearSearch() method from app/bar.js. (
app/bar.js:251) - Integrated mixinFormAssociated with getFormValue, formResetCallback(), and formStateRestoreCallback() on . (
search/search.js:39) - Added outline: none to :host on to prevent duplicate focus rings in Chromium when using delegatesFocus: true. (
search/search.js:517)
🔍 General Feedback
- The integration between and is well-crafted; leveraging composed bubbling events enables search submissions to seamlessly cross shadow DOM boundaries without redundant event wrapping.
- The inclusion of :host([hidden]) { display: none; } across list-item.js and menu-item.js alongside the ::slotted([hidden]) style rule ensures suggestion filtering works reliably regardless of slotted element type.
- The search bar fill colors (--_search-container-color and --_scrolled-search-container-color) provide clean contrast between the app bar surface and the search input in both resting and scrolled states.
📊 Token Usage & Cost Efficiency
| Metric | Value |
|---|---|
| Input Tokens (uncached) | 84,711 |
| Input Tokens (cached) | 427,723 (⚡ 82.9% cached) |
| PR Comments History Tokens | 3,389 |
| Thinking / Reasoning Tokens | 20,943 |
| Output Tokens | 1,214 |
| Total Session Tokens | 537,980 |
| Cost (uncached input) | $0.0661 |
| Cost (cached input) | $0.0321 |
| Cost (thinking / reasoning) | $0.0785 |
| Cost (response output) | $0.0046 |
| Estimated Total Cost | $0.1812 |
Gemini 3.8 Flash: introductory rate $0.75/$3.75 per 1M applied; reverts to $1.5/$7.5 after 2026-12-31.
Gemini 3.8 Flash: standard tier; batch and flex are half again, priority is higher.
Cache reads are priced here, but context-cache STORAGE, where the model charges for it separately per token-hour, is not included, so the figure can run slightly low.
There was a problem hiding this comment.
📋 Review Summary
This update aligns the Search Bar and App Bar search variant with the Material Design 3 Search specification, introducing adaptive docked and full-screen Search Views, automatic suggestion filtering, and form association via mixinFormAssociated. Previous review comments regarding focusout handling and focus containment have been incorporated.
✅ Resolved Items from Prior Reviews
- Added
_handleFocusouthandler checking related targets to cleanly close the search view when focus leaves<md-search>. (search/search.js:170) - Bound
@focusout=${this._handleFocusout}to the search wrapper element. (search/search.js:435)
🔍 General Feedback
- The integration of
<md-search>directly into<md-app-bar>provides a consistent Material 3 experience with clean handling of docked and full-screen view transitions. - Form integration with
mixinFormAssociatedandElementInternalsproperly reflects search values in native<form>submissions. - Supporting both slotted
<md-menu-item>and<md-list-item>components in suggestions allows versatile presentation in both docked and full-screen modes.
📊 Token Usage & Cost Efficiency
| Metric | Value |
|---|---|
| Input Tokens (uncached) | 85,049 |
| Input Tokens (cached) | 427,723 (⚡ 82.8% cached) |
| PR Comments History Tokens | 3,777 |
| Thinking / Reasoning Tokens | 98 |
| Output Tokens | 306 |
| Total Session Tokens | 516,953 |
| Cost (uncached input) | $0.0666 |
| Cost (cached input) | $0.0321 |
| Cost (thinking / reasoning) | $0.0004 |
| Cost (response output) | $0.0011 |
| Estimated Total Cost | $0.1002 |
Gemini 3.8 Flash: introductory rate $0.75/$3.75 per 1M applied; reverts to $1.5/$7.5 after 2026-12-31.
Gemini 3.8 Flash: standard tier; batch and flex are half again, priority is higher.
Cache reads are priced here, but context-cache STORAGE, where the model charges for it separately per token-hour, is not included, so the figure can run slightly low.
Summary
Aligns
<md-search>(search/search.js) and<md-app-bar>(app/bar.js) with the Material Design 3 Search Bar and App Bar specifications.Key Changes
<md-search>(search/search.js):<md-text-field>wrapper with a dedicated 56px full-pill (9999px) contained surface (--md-sys-color-surface-container-high),<md-elevation>(elevatedattribute for level 3 resting elevation), hover/pressed state layers, and<md-focus-ring>.<input type="search">withbody-largetypography (--md-sys-color-on-surfaceinput text and--md-sys-color-on-surface-variantsupporting/hint text) and no floating notched label.<md-icon-button aria-label="Clear search">when text is entered (no-clearto disable), keeps<slot name="trailing-icon">persistently visible for trailing actions, and adds<slot name="avatar">(30pxcircular avatar).center-aligned,disabled,elevated,no-clear, reactivevaluesynchronization, andinput,change,search, andclearevents.<md-app-bar>(app/bar.js):type="search"to compose<md-search>with--md-sys-color-surface-containerwhen unscrolled and--md-sys-color-surface-container-highestwhenscrolled.center-alignedacrossmedium-flexible,large-flexible, andsearchvariants in addition tosmall.16pxleading inset when nonavigation-iconis slotted.400(title-large) and enabled 2-line wrapping on expanded flexible headlines.search/search.jsinall.jsand updatedsearch/README.md,app/README.md, anddemo/app-bar-demo.html.Verification
node --check) acrosssearch/search.js,app/bar.js, andall.js.