PlFloatingActionButton
The one action a screen is about, floating over it. A PlButton in a corner, plus the pinning, the shape, and one rule: the label always exists, whether or not it is drawn.
import { PlFloatingActionButton } from 'plass-ui';
<PlFloatingActionButton icon={<PlusGlyph />} label="New project" onClick={create} />;import 'package:plass_ui/plass_ui.dart';
PlFloatingActionButton(
icon: const PlusGlyph(),
label: 'New project',
onPressed: create,
);Props
| Prop | Type | Default | Description |
|---|---|---|---|
| icon * | ReactNode | — | The glyph |
| label * | string | — | What the button does. The accessible name whether or not the words are drawn |
| extended | boolean | false | Draws the label beside the glyph |
| corner | 'top-start' | 'top-end' | 'bottom-start' | 'bottom-end' | 'bottom-end' | Which corner of the window it sits in. start/end rather than left/right |
| offset | number | string | '1.5rem' | How far it stands off the two edges it is against |
| floating | boolean | true | Whether it pins itself to the window. Off keeps the shape and the shadow and drops the positioning |
| variantshared | 'solid' | 'glass' | 'ghost' | 'solid' | What the key is made of |
| sizeshared | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'lg' | One step up from a PlButton's. A floating button is a target for a thumb |
| elevationshared | 0 | 1 | 2 | 3 | 3 | The top of the ladder. This is the one control that genuinely floats over the content rather than resting on it |
| Prop | Type | Default | Description |
|---|---|---|---|
| icon * | Widget | — | The glyph |
| label * | String | — | What the button does. The accessible name whether or not the words are drawn |
| onPressed | VoidCallback? | — | What pressing it does. Leaving it null disables the button |
| extended | bool | false | Draws the label beside the glyph |
| corner | PlassCorner | PlassCorner.bottomEnd | Which corner of the window it sits in. start/end rather than left/right |
| offset | double | 24 | How far it stands off the two edges it is against |
| floating | bool | true | Whether it pins itself to the window. Off keeps the shape and the shadow and drops the positioning |
| variantshared | PlassVariant | PlassVariant.solid | What the key is made of |
| sizeshared | PlassSize | PlassSize.lg | One step up from a PlButton's. A floating button is a target for a thumb |
| elevationshared | int | 3 | The top of the ladder. This is the one control that genuinely floats over the content rather than resting on it |
Everything a PlButton takes, it takes: the three materials, the elevation ladder, the pointer light, loading, readOnly and disabled. What the shared axes mean is in prop conventions.
label is not optional
A floating button is a disc with a mark in it nine times out of ten. extended decides whether the words are also drawn, never whether they exist.
That is why label is required and is always the accessible name. An icon-only button with no name is the single most common accessibility defect this pattern ships with, and making the prop required is the only fix that survives review.
import { PlFloatingActionButton } from 'plass-ui';
function Plus() {
return (
<svg viewBox="0 0 16 16" fill="none" aria-hidden="true">
<path d="M8 3.5v9M3.5 8h9" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" />
</svg>
);
}
export default function FloatingActionButtonExtended() {
return (
<div className="flex items-center justify-center gap-5">
<PlFloatingActionButton floating={false} icon={<Plus />} label="New project" />
<PlFloatingActionButton floating={false} extended icon={<Plus />} label="New project" />
</div>
);
}import 'package:flutter/widgets.dart';
import 'package:plass_ui/plass_ui.dart';
class _Plus extends StatelessWidget {
const _Plus();
@override
Widget build(BuildContext context) {
return const SizedBox.square(dimension: 20, child: FittedBox(child: Text('+')));
}
}
class FloatingActionButtonExtended extends StatelessWidget {
const FloatingActionButtonExtended({super.key});
@override
Widget build(BuildContext context) {
return SizedBox(
width: 360,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
spacing: 20,
children: <Widget>[
PlFloatingActionButton(
floating: false,
icon: const _Plus(),
label: 'New project',
onPressed: () {},
),
PlFloatingActionButton(
floating: false,
extended: true,
icon: const _Plus(),
label: 'New project',
onPressed: () {},
),
],
),
);
}
}Turn extended on for an action a first-time reader would not guess from a glyph, and off again once they would.
The two shapes
The icon-only form is a disc. That is PlIconButton's deliberate exception to the radius rule: the flat run along a control's edge is there for a line of text to sit on, and a glyph has no line of text.
The extended form is not a pill, for exactly that reason. It has words along its edge, so it takes the house fillet like every other labelled control.
One per screen
Two floating buttons in one corner is two primary actions, which is none.
And a screen whose main action is already a button in the content does not want a second copy of it in the corner. The floating one is for the action that has nowhere else to live, on a screen that is a list of things you are about to add to.
Examples
Somewhere other than the bottom trailing corner
corner is one of the four, spelled start/end rather than left/right so the button crosses the screen under RTL with everything else. offset is how far it stands off the two edges it is against.
<PlFloatingActionButton corner="bottom-start" offset={16} icon={<PlusGlyph />} label="Add" />In the flow instead
floating={false} keeps the shape and the shadow and drops the positioning, for the same button at the end of a card or in a toolbar.
<PlFloatingActionButton floating={false} extended icon={<PlusGlyph />} label="New project" />Notes
elevationdefaults to 3, the top of the ladder, and unlike every other default in the library it is not a compromise: this is the one control that genuinely floats over the content rather than resting on it.sizedefaults tolg, one step up from aPlButton's. A floating button is a target for a thumb.
- It is
position: fixedwith logical insets, written inline: a caller'soffsetis a value rather than a class, and an inline declaration is the one form that wins over a utility deterministically. - It sits at
z-30, the same level aPlBackTopdoes, above the page and below anything portalled.
- While
floatingit is aPositionedDirectional, so it belongs in aStack, which is what a screen's body usually already is once anything floats over it.
Accessibility
- The name is
label, always, and it is the same wordsextendedwould draw. There is no way to make one of these without a name. - It is a real button and nothing else: it takes the focus in document order, answers Enter and Space, and reports
loadinganddisabledexactly as aPlButtondoes. - It covers content. A button pinned to a corner sits over whatever is under it, so leave room for it at the end of a scrolling list. The last row of a list under a floating button is a row nobody can press.