Skip to content

PlIconButton

A round button with a glyph in it and nothing else. Everything about it is a PlButton except the shape and the one prop that is required. The words the drawing does not say.

React
tsx
import { PlIconButton } from 'plass-ui';

<PlIconButton icon={<TrashIcon />} label="Delete" variant="glass" color="danger" />;
dart
import 'package:plass_ui/plass_ui.dart';

PlIconButton(
  icon: const Icon(Icons.delete_outline),
  label: 'Delete',
  variant: PlassVariant.glass,
  color: PlassColor.danger,
  onPressed: remove,
);

Props

PropTypeDefaultDescription
variantshared'solid' | 'glass' | 'ghost''solid'What the surface is made of: tinted glass, a clear sheet, or nothing
sizeshared'xs' | 'sm' | 'md' | 'lg' | 'xl''md'The disc's diameter and the glyph inside it — the same ladder as PlButton
colorshared'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info''primary'Semantic colour role. Arbitrary colour values are not accepted
densityshared'default' | 'compact''default'Padding only — never the height, never the type scale
elevationshared0 | 1 | 2 | 31Drop shadow depth. 0 means no shadow at all
icon * ReactNodeThe glyph. Passed bare it is sized in em against the button
label * stringWhat the button does, in words. It becomes the accessible name and is never drawn
loadingbooleanfalseShows a spinner in place of the glyph and stops the button activating, while keeping it focusable
readOnlybooleanfalseKeeps its colour, goes flat and drains most of its saturation — not dimmed
disabledbooleanfalseUnavailable. Loses its light and its shadow, and leaves the focus order
renderRenderPropRenders something other than a <button> (<a href="…" />)
PropTypeDefaultDescription
icon * WidgetThe glyph. Passed bare it is sized in em against the button
label * StringWhat the button does, in words. It becomes the accessible name and is never drawn
onPressedVoidCallback?Called when the button is activated. Leaving it null disables the button
onLongPressVoidCallback?Called on a long press
variantsharedPlassVariant?PlassVariant.solidWhat the surface is made of: tinted glass, a clear sheet, or nothing
sizesharedPlassSize?PlassSize.mdThe disc's diameter and the glyph inside it — the same ladder as PlButton
colorsharedPlassColor?PlassColor.primarySemantic colour role. Arbitrary colour values are not accepted
elevationsharedint?1Drop shadow depth. 0 means no shadow at all
loadingboolfalseShows a spinner in place of the glyph and stops the button activating, while keeping it focusable
readOnlyboolfalseKeeps its colour, goes flat and drains most of its saturation — not dimmed
disabledbool?falseUnavailable. Loses its light and its shadow, and leaves the focus order
focusNode · autofocusFocusNode? · boolDrive focus from outside, or take it on insertion

Every prop PlButton takes passes through untouched except children, startIcon and endIcon, which the glyph has taken over. Every native <button> attribute passes through as well.

Every parameter PlButton takes passes through except child, startIcon, endIcon and fullWidth. The glyph has taken the first three, and a disc that stretches is not a disc. There is no density either: it changes horizontal padding, and an icon-only button has none.

What the shared axes (variant size color density elevation) mean across the library is in prop conventions.

Examples

label

Required, and the one prop here that is.

A button whose whole label is a drawing has no accessible name at all, and "an icon button with no aria-labelsemantic label" is the single most common accessibility defect a component library ships. Making it required is the only fix that survives review. A lint rule is something a project has to install and a default of '' is something nobody notices.

It is never drawn. What a reader sees is the glyph; what everything else reads is the sentence.

The shape

A PlButton with an icon and no label already goes square, same height, same width, the house fillet cut off it. This is the other shape: a disc.

That disc is a deliberate exception to the radius rule, which holds every corner well short of the 50% that would make a control a pill. The rule is about labelled controls: the flat run along the top and bottom edge is where a line of text sits, and a glyph has no line of text. A circle with a single mark centred in it reads as a punched token rather than a moulded key.

React

size

The same height ladder as PlButton, so a disc and a labelled button on one row keep their baseline. The glyph inside is sized in em against the button rather than off the standalone-icon ladder, which is what keeps it in proportion at every step.

React

color

React

loading, readOnly and disabled

All three are PlButton's, unchanged. loading puts a spinner where the glyph was and stops the button firing while leaving it focusable; readOnly keeps the colour and drains the saturation; disabled takes the light out and leaves the focus order.

React

Accessibility

  • label is the accessible name and it is required. Nothing else here can supply one.
  • The glyph is decorative. It is inside a control that is already named, so a second name from the drawing would be the name read twice.
  • Everything else is PlButton's: the focus ring, the keyboard activation, aria-busy while loading, and dropping out of the focus order only when disabled.
  • The disc is still a real <button>. render={<a href="…" />} makes it a real link instead, announced as one and followed by a crawler.

Differences from the React build

ReactFlutterWhy
onClickonPressedFlutter's name, and leaving it out is how a button is disabled.
renderThere is no element to swap and no link semantics to claim.
density, fullWidthDensity changes horizontal padding, which an icon-only button has none of; a disc that stretches is not a disc.
an inline style for the radiusPlButton.borderRadiusFlutter has no inline style, so PlButton carries one escape hatch and this is the widget it exists for.
className, styleThere is no class list and no style attribute to pass through.

The radius is half the control height rather than a number large enough to be clamped: the paint scales a radius that is too big for its box, and a disc scaled that way stops being one at the ends.

Released under the MIT License