Hide a disabled fab button on a compact window, as M3 removes a FAB
`<x-button fab>` is an extended FAB below `medium` and a filled button from there, but a disabled one was still drawn as the FAB below `medium`: the compact FAB's rule set no state of its own, so the button stood greyed out and fixed over the content. M3 never disables a FAB: "if its action is unavailable, remove the FAB entirely". A `fab` given `disabled` (a `<button disabled>`, or a link's `aria-disabled="true"`) now renders `data-md-unavailable`, and button.css draws it `display: none` below `medium`, which also takes it out of the accessibility tree and the Tab order; from `medium` it is the disabled filled button it was. The mark comes from the prop, not from `:disabled`, because a `spinner` puts `disabled` on its button while the action runs, and that FAB is busy rather than unavailable: hidden, it would vanish instead of showing its loading indicator. The docblocks and the skill's button table say so. A browser test renders an enabled fab with a slow spinner action, a disabled one and a disabled link on a 393px window: the disabled two are not rendered, the busy one stays on screen with its indicator, and at 600px both disabled ones are the disabled button again; it fails without the change in Chrome, Firefox and Safari (and in Chrome with `:disabled` alone as the condition, on the busy FAB). A feature test reads the mark and the rule. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
cf63f11bfb
commit
6d4487feb3
@@ -263,7 +263,7 @@ Label button, icon button, toggle and responsive FAB in one component.
|
||||
| `link`, `external`, `no-wire-navigate` | | renders `<a>`, with `wire:navigate` unless external |
|
||||
| `spinner` | | `true` shows the loading indicator while its `wire:click` runs; a string names the action |
|
||||
| `tooltip`, `tooltip-left`, `tooltip-right`, `tooltip-bottom` | | plain tooltip; also the icon button's accessible name |
|
||||
| `disabled`, `type`, `responsive`, `fab` | | `responsive` hides the label below `expanded`; `fab` is an extended FAB on a compact window (below `medium`), a filled button from there |
|
||||
| `disabled`, `type`, `responsive`, `fab` | | `responsive` hides the label below `expanded`; `fab` is an extended FAB on a compact window (below `medium`), a filled button from there; a `disabled` fab is not drawn below `medium` — M3 removes a FAB whose action is unavailable — and is the disabled button from there (a `spinner` disabling it while its action runs leaves it on screen) |
|
||||
|
||||
```blade
|
||||
<x-button label="Create link" icon="link" variant="filled" size="md" wire:click="create" spinner />
|
||||
|
||||
@@ -44,7 +44,9 @@
|
||||
* primary-container at elevation 3 (ExtendedFabPrimaryTokens) — lifted clear of a bottom bar and
|
||||
* of a snackbar on screen (`--material-bottom-bar`, `--material-snackbar-height`), because M3 puts a
|
||||
* snackbar above a FAB and never over one. From `medium` it is the button it was written as.
|
||||
* `data-md-responsive` on the label hides it below `expanded` (840px).
|
||||
* `data-md-unavailable`, a `fab` given `disabled`, is not drawn below `medium`: M3 never shows a
|
||||
* disabled FAB, but removes one whose action is unavailable. From `medium` it is the disabled
|
||||
* button. `data-md-responsive` on the label hides it below `expanded` (840px).
|
||||
*/
|
||||
|
||||
@layer material.reset, material.tokens, material.base, material.layout, material.components, material.text, material.visibility;
|
||||
@@ -397,5 +399,12 @@
|
||||
inline-size: 24px;
|
||||
block-size: 24px;
|
||||
}
|
||||
|
||||
/* M3 never disables a FAB: "if its action is unavailable, remove the FAB entirely"
|
||||
(docs/reference/m3/components-actions-communication-containment.md § FAB). Not drawn,
|
||||
it is out of the accessibility tree and the Tab order too. */
|
||||
[data-md-button][data-md-compact-fab][data-md-unavailable] {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,9 @@
|
||||
pinned in the thumb zone on a compact window (below `medium`, 600px), a filled button from
|
||||
there — one element either way. It lifts clear of a bottom bar and of a snackbar on screen
|
||||
(`--material-bottom-bar`, `--material-snackbar-height`), because M3 puts a snackbar above a
|
||||
FAB and never over one.
|
||||
FAB and never over one. A `fab` that is `disabled` is not drawn below `medium`, since M3
|
||||
removes a FAB whose action is unavailable rather than showing it disabled, and is the disabled
|
||||
filled button from there; a spinner's own disabling while the action runs leaves it on screen.
|
||||
|
||||
The view renders the props as `data-md-*` attributes and resources/css/components/button.css
|
||||
draws them, in the package's components layer: a caller's class or unlayered CSS outranks
|
||||
@@ -124,6 +126,9 @@
|
||||
'data-md-width' => $iconOnly ? $width : null,
|
||||
'data-md-selected' => $selected === null ? null : ($selected ? 'true' : 'false'),
|
||||
'data-md-compact-fab' => $fab ? true : null,
|
||||
// Read from the prop, not from `:disabled`: a spinner disables its button while the action
|
||||
// runs, and that FAB is busy, not unavailable.
|
||||
'data-md-unavailable' => $fab && $disabled ? true : null,
|
||||
'href' => $isLink ? $link : null,
|
||||
'target' => $isLink && $external ? '_blank' : null,
|
||||
'rel' => $isLink && $external ? 'noopener' : null,
|
||||
|
||||
Reference in New Issue
Block a user