From d706eef01b9e2091f70230667fd990185684503f Mon Sep 17 00:00:00 2001 From: Andreas Reinhold / reini Date: Mon, 14 Sep 2026 17:05:56 +0200 Subject: [PATCH] Opt the select into base-select from its own stylesheet Plan step 36. menu.css left Tailwind's unlayered half for material.components, where its `appearance: base-select` on the select ties select.css's `appearance: none` in layer and specificity and loses on order: select.css's block always follows the menu.css it imports. The customizable select would have fallen back to the native list. The select's own opt-in now sits in select.css's @supports block; menu.css keeps the picker's. A test pins where each is written. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9 --- resources/css/components/menu.css | 4 +++- resources/css/components/select.css | 1 + tests/Feature/Components/MenuTest.php | 13 ++++++++++++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/resources/css/components/menu.css b/resources/css/components/menu.css index bbd05694..172f6672 100644 --- a/resources/css/components/menu.css +++ b/resources/css/components/menu.css @@ -320,7 +320,9 @@ } @supports (appearance: base-select) { - select[data-md-field-control], + /* The select itself opts in from select.css, after its own `appearance: none`: both sit in + `material.components` with the same specificity, and select.css's block always comes + after this file, which it imports. */ select[data-md-field-control]::picker(select) { appearance: base-select; } diff --git a/resources/css/components/select.css b/resources/css/components/select.css index 965f7326..6b024754 100644 --- a/resources/css/components/select.css +++ b/resources/css/components/select.css @@ -43,6 +43,7 @@ the arrow turns over, as the searchable choices' does. */ @supports (appearance: base-select) { select[data-md-field-control] { + appearance: base-select; display: flex; align-items: center; border: 0; diff --git a/tests/Feature/Components/MenuTest.php b/tests/Feature/Components/MenuTest.php index 2dcc4ff1..31f587a8 100644 --- a/tests/Feature/Components/MenuTest.php +++ b/tests/Feature/Components/MenuTest.php @@ -392,7 +392,18 @@ it('draws the dropdown a select or a searchable choices field opens, the same fa 'background-color' => 'var(--md-sys-color-secondary-container)', 'color' => 'var(--md-sys-color-on-secondary-container)', ]) - ->and($css->css)->toContain('@supports (appearance: base-select) {') + ->and($css->declarations('select[data-md-field-control]::picker(select)', ['@supports (appearance: base-select)']))->toMatchArray(['appearance' => 'base-select']) ->and(ComponentStylesheet::read('select')->imports())->toContain('./menu.css') ->and(ComponentStylesheet::read('choices')->imports())->toContain('./menu.css'); }); + +it('opts the select itself into the customizable select after its own appearance: none', function () { + // menu.css and select.css share `material.components` and the selector's specificity, and + // select.css's block always follows the menu.css it imports: the opt-in has to be written + // there, or `appearance: none` wins and the picker is never the menu. + $select = ComponentStylesheet::read('select'); + + expect($select->declarations('select[data-md-field-control]'))->toMatchArray(['appearance' => 'none']) + ->and($select->declarations('select[data-md-field-control]', ['@supports (appearance: base-select)']))->toMatchArray(['appearance' => 'base-select']) + ->and(ComponentStylesheet::read('menu')->has('select[data-md-field-control]', ['@supports (appearance: base-select)']))->toBeFalse(); +});