Basic Floating Action Button
A round, fixed icon button for the one action a screen is really about - with a ring that survives any backdrop.
6 frameworksBeginner
A round FAB whose label appears on hover and on focus - while the real accessible name lives on the button.
<!--
Two things carry the label and they are NOT the same mechanism:
aria-label → the accessible name. This is what a screen reader announces.
the tooltip → a visual affordance for sighted mouse/keyboard users.
A tooltip alone is not a name - it is a popup that may never be announced,
and it does not exist at all on touch. So the button keeps its aria-label and
the tooltip is aria-hidden: the name is stated once, the bubble is pure
decoration, and they cannot disagree because both read from the same source.
The tooltip appears on :hover AND :focus-visible. Hover-only would make it
mouse-only - exactly the users who need it least.
-->
<div class="tip-fab">
<button class="tip-fab__button" type="button" aria-label="Start a call">
<svg class="tip-fab__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false">
<path d="M22 16.9v3a2 2 0 0 1-2.2 2 19.8 19.8 0 0 1-8.6-3.1 19.5 19.5 0 0 1-6-6A19.8 19.8 0 0 1 2.1 4.2 2 2 0 0 1 4.1 2h3a2 2 0 0 1 2 1.7c.1 1 .4 1.9.7 2.8a2 2 0 0 1-.5 2.1L8.1 9.9a16 16 0 0 0 6 6l1.3-1.3a2 2 0 0 1 2.1-.4c.9.3 1.8.6 2.8.7a2 2 0 0 1 1.7 2Z" />
</svg>
</button>
<span class="tip-fab__tooltip" aria-hidden="true">Start a call</span>
</div>| Prop | Type | Default | Description |
|---|---|---|---|
labelrequired | string | - | Accessible label announced while loading. |
icon | ReactNode | - | Icon element rendered alongside the content. |
onClick | () => void | - | Fired when the user activates the control. |
className | string | - | Additional classes merged onto the root element. |
The trap this component exists to avoid: **a tooltip is not an accessible name.** It is a popup that assistive tech may never announce, that does not exist at all on touch, and that vanishes the moment the pointer leaves. So the button keeps its `aria-label` and the bubble is `aria-hidden` - the name is stated once where it counts, the bubble is a picture of it for sighted users, and both read from the same `label` prop so they cannot disagree. The second detail is `peer-focus-visible` sitting alongside `peer-hover`: a tooltip that only answers to the mouse is invisible to exactly the keyboard users who most need to know what an unlabelled circle does. The bubble inverts in dark mode (`bg-gray-900` → `dark:bg-gray-50`) rather than staying dark, because a tooltip has to read as a foreground object on both themes. `pointer-events-none` keeps it from ever sitting between the cursor and the button it describes.