Button reveal
One button that unfolds into several when the pointer reaches it. The compact form of a toolbar that would otherwise take a whole row - and the revealed buttons are ordinary icon buttons, so they behave exactly as they would anywhere else.
Hover to reveal
Closed, the cluster is one button. Bring the pointer to it and the actions unroll beside it, each arriving a moment after the one before. Keyboard focus reveals them too - tab to the trigger and the cluster opens, then Tab walks into the actions - so hover is never the only way in.
<VetoButtonReveal Icon="@VetoIcons.Share" Label="Share" Round="true">
<VetoIconButton Icon="@VetoIcons.GitHub" Label="GitHub" OnClick="ShareToGitHub" />
<VetoIconButton Icon="@VetoIcons.X" Label="X" OnClick="ShareToX" />
<VetoIconButton Icon="@VetoIcons.LinkedIn" Label="LinkedIn" OnClick="ShareToLinkedIn" />
<VetoIconButton Icon="@VetoIcons.Mail" Label="Email" OnClick="ShareByEmail" />
</VetoButtonReveal>A trigger that does something itself
Without OnClick the trigger is a disclosure and a click toggles the cluster - which is what makes it usable on a touch screen, where there is no hover. Give it OnClick and it becomes a real action instead: the click runs the default - Save - and the cluster stays the pointer's shortcut to the variants.
@* With OnClick the trigger is an action, not a disclosure: the click saves, and the
cluster is the shortcut to the variants. *@
<VetoButtonReveal Icon="@VetoIcons.Save" Label="Save" ShowLabel="true" OnClick="SaveAsync">
<VetoIconButton Icon="@VetoIcons.Copy" Label="Save a copy" OnClick="SaveCopyAsync" />
<VetoIconButton Icon="@VetoIcons.Download" Label="Save and download" OnClick="SaveAndDownloadAsync" />
</VetoButtonReveal>Directions
The cluster unfolds whichever way suits where the trigger sits - out to either side, up, or down. Start and Up put the actions before the trigger on screen while leaving the trigger first in the DOM, so Tab still reaches the trigger before the actions it discloses.
<VetoButtonReveal Icon="@VetoIcons.ChevronRight" Label="Out to the end">…</VetoButtonReveal>
<VetoButtonReveal Icon="@VetoIcons.ChevronLeft" Label="Out to the start"
Direction="VetoRevealDirection.Start">…</VetoButtonReveal>
<VetoButtonReveal Icon="@VetoIcons.ChevronDown" Label="Downwards"
Direction="VetoRevealDirection.Down">…</VetoButtonReveal>
<VetoButtonReveal Icon="@VetoIcons.ChevronUp" Label="Upwards"
Direction="VetoRevealDirection.Up">…</VetoButtonReveal>Opening on a click instead
Hover is right for a cluster beside the thing it acts on. For one that should not open in passing - a row of destructive actions, or a cluster in a dense table - a click is the better trigger, and the cluster then ignores the pointer merely crossing it.
<VetoButtonReveal Icon="@VetoIcons.MoreHorizontal" Label="Row actions"
OpenOn="VetoRevealTrigger.Click"
Variant="VetoVariant.Outlined" Color="VetoColor.Neutral">
<VetoIconButton Icon="@VetoIcons.Edit" Label="Edit" />
<VetoIconButton Icon="@VetoIcons.Archive" Label="Archive" />
<VetoIconButton Icon="@VetoIcons.Trash" Label="Delete" Color="VetoColor.Danger" />
</VetoButtonReveal>Sizes, variants and spacing
The trigger takes the same size, variant and colour scale as VetoButton, so a cluster sits in a toolbar beside ordinary buttons without looking imported. Stagger can be turned off for a cluster that should appear whole, and it is ignored anyway for a reader who asked for reduced motion.
<VetoButtonReveal Icon="@VetoIcons.Plus" Label="Small" Size="VetoSize.Small" Round="true">…</VetoButtonReveal>
<VetoButtonReveal Icon="@VetoIcons.Plus" Label="Large" Size="VetoSize.Large" Round="true">…</VetoButtonReveal>
@* Appears whole rather than unrolling, with a wider gap. *@
<VetoButtonReveal Icon="@VetoIcons.Bolt" Label="All at once"
Stagger="false" Gap="VetoSpacing.Medium"
Variant="VetoVariant.Text" Color="VetoColor.Primary">…</VetoButtonReveal>Reach without a pointer
A cluster that only opened on hover would put its actions out of reach of anyone
using a keyboard, and out of reach entirely on a touch screen. So there are three
ways in, and the component keeps all of them: the pointer arriving,
keyboard focus landing anywhere in the cluster, and a
tap or click on the trigger. Esc closes it and returns
focus to the trigger.
While the cluster is closed the actions stay in the DOM but are marked
inert, so they hold their place in the layout - which is what lets the
reveal be a transition rather than a jump - while taking no focus and going
unannounced. That is also why focus can move into them the moment the cluster opens,
with no second render to wait for.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
Icon |
string? |
— |
The trigger's icon. |
Label |
string? |
— |
The trigger's accessible name, and the cluster's group label. Always supply one. |
ShowLabel |
bool |
false |
Whether the label is drawn beside the icon. |
Tooltip |
string? |
Label |
The trigger's tooltip. |
ActionsLabel |
string? |
Label |
The revealed group's accessible name, when it should differ. |
TriggerContent |
RenderFragment? |
— |
Replaces the trigger's contents; the button element stays the component's. |
Expanded |
bool |
false |
Whether the actions are showing. Supports @bind-Expanded. |
ExpandedChanged |
EventCallback<bool> |
— |
Raised when the cluster opens or closes. |
OpenOn |
VetoRevealTrigger |
Hover |
Hover or Click. Focus and touch work either way. |
Direction |
VetoRevealDirection |
End |
Which way the actions unfold: End, Start, Up or Down. |
Size |
VetoSize |
Medium |
The trigger's size. The revealed buttons keep their own. |
Variant |
VetoVariant |
Filled |
The trigger's visual treatment. |
Color |
VetoColor |
Primary |
The trigger's colour role. |
Round |
bool |
false |
Draws the trigger as a circle - the speed-dial look. |
Gap |
VetoSpacing |
ExtraSmall |
The gap between the revealed buttons. |
Stagger |
bool |
true |
Whether each action arrives after the one before it. |
OpenDelay |
int |
0 |
Milliseconds the pointer must rest before the cluster opens. |
CloseDelay |
int |
240 |
Milliseconds the cluster stays open after the pointer leaves. |
Disabled |
bool |
false |
Disables the trigger and closes the cluster. |
OnClick |
EventCallback<MouseEventArgs> |
— |
Makes the trigger a real action rather than a disclosure. |