FAB
A floating action button carries the primary action of a screen. Use one per screen, for the action people come to that screen to do.
Usage
A FAB shows an icon and no text, so give it a label. It becomes the accessible name
and a tooltip, the same way title works on a Button.
<script lang="ts">
import { Fab } from 'noph-ui'
import { Icon } from 'noph-ui/icons'
</script>
<Fab label="Add">
{#snippet icon()}<Icon>add</Icon>{/snippet}
</Fab>
Sizes
Three sizes, 56, 80 and 96 pixels, the same three an ExtendedFab takes. s is M3's baseline FAB and the default; reach for a bigger one when the FAB is competing
with a large hero image. There is no 40 pixel FAB, because M3 Expressive no longer recommends one.
<script lang="ts">
import { Fab } from 'noph-ui'
import { Icon } from 'noph-ui/icons'
</script>
<Fab size="s" label="Add, small">
{#snippet icon()}<Icon>add</Icon>{/snippet}
</Fab>
<Fab size="m" label="Add, medium">
{#snippet icon()}<Icon>add</Icon>{/snippet}
</Fab>
<Fab size="l" label="Add, large">
{#snippet icon()}<Icon>add</Icon>{/snippet}
</Fab>
Colors
Six color styles, each named after the tokens it maps to. The three tone styles are the stronger pair and the three container styles the softer one; pick whichever stands out against the surface behind it. There is no surface style, because M3 Expressive no longer recommends one.
<script lang="ts">
import { Fab } from 'noph-ui'
import { Icon } from 'noph-ui/icons'
</script>
<Fab variant="primary" label="Primary">
{#snippet icon()}<Icon>add</Icon>{/snippet}
</Fab>
<Fab variant="secondary" label="Secondary">
{#snippet icon()}<Icon>mail</Icon>{/snippet}
</Fab>
<Fab variant="tertiary" label="Tertiary">
{#snippet icon()}<Icon>favorite</Icon>{/snippet}
</Fab>
<script lang="ts">
import { Fab } from 'noph-ui'
import { Icon } from 'noph-ui/icons'
</script>
<Fab variant="primary-container" label="Primary container">
{#snippet icon()}<Icon>add</Icon>{/snippet}
</Fab>
<Fab variant="secondary-container" label="Secondary container">
{#snippet icon()}<Icon>mail</Icon>{/snippet}
</Fab>
<Fab variant="tertiary-container" label="Tertiary container">
{#snippet icon()}<Icon>favorite</Icon>{/snippet}
</Fab>
Shape
round is fully rounded and square is a tighter radius, reading the same
way as on Button. Either way, a press morphs the
corner towards the other shape.
<script lang="ts">
import { Fab } from 'noph-ui'
import { Icon } from 'noph-ui/icons'
</script>
<Fab shape="round" label="Round">
{#snippet icon()}<Icon>add</Icon>{/snippet}
</Fab>
<Fab shape="square" label="Square">
{#snippet icon()}<Icon>add</Icon>{/snippet}
</Fab>
Lowered
lowered drops the shadow a level, for a FAB sitting on a surface that is already raised,
such as inside a card or a sheet.
<script lang="ts">
import { Fab } from 'noph-ui'
import { Icon } from 'noph-ui/icons'
</script>
<Fab label="Default elevation">
{#snippet icon()}<Icon>add</Icon>{/snippet}
</Fab>
<Fab lowered label="Lowered">
{#snippet icon()}<Icon>add</Icon>{/snippet}
</Fab>
Extended
An extended FAB shows its label as text, so it names itself and needs no tooltip. Use it when the action is not obvious from an icon alone.
<script lang="ts">
import { ExtendedFab } from 'noph-ui'
import { Icon } from 'noph-ui/icons'
</script>
<ExtendedFab label="Compose">
{#snippet icon()}<Icon>mail</Icon>{/snippet}
</ExtendedFab>
<ExtendedFab variant="tertiary" label="Search">
{#snippet icon()}<Icon>search</Icon>{/snippet}
</ExtendedFab>
Collapsing
collapsed shrinks an extended FAB to the icon alone and animates the width. Drive it
from whatever you already track, a scroll position or a media query. The label moves to aria-label while it is collapsed, so the button keeps its name.
<script lang="ts">
import { ExtendedFab, Switch } from 'noph-ui'
import { Icon } from 'noph-ui/icons'
let collapsed = $state(false)
</script>
<label style="display:inline-flex;align-items:center;gap:0.5rem">
<Switch bind:selected={collapsed} />
Collapsed
</label>
<ExtendedFab {collapsed} label="Compose">
{#snippet icon()}<Icon>mail</Icon>{/snippet}
</ExtendedFab>
FAB menu
A FAB menu turns the FAB into a set of related actions. The trigger becomes square and its icon
turns into a close affordance while the menu is open, and the items rise into place one after
another. placement decides which side they fan out to. Picking an action closes the
menu; pass closeOnSelect=false to keep it open for actions that toggle something.
variant colours the trigger. The items are your own buttons, so pair them with it
yourself: set the tonal Button tokens on the FabMenu and every item inherits
them.
<script lang="ts">
import { Button, FabMenu } from 'noph-ui'
import { Icon } from 'noph-ui/icons'
</script>
<div style="display:flex;justify-content:center;padding-block-start:9rem;width:16rem">
<FabMenu label="Create">
{#snippet icon()}<Icon>add</Icon>{/snippet}
<Button variant="tonal">New document</Button>
<Button variant="tonal">New folder</Button>
<Button variant="tonal">Upload</Button>
</FabMenu>
</div>
<div style="display:flex;justify-content:center;padding-block-start:9rem;width:16rem">
<FabMenu
label="Create, tertiary"
variant="tertiary"
style="--np-tonal-button-container-color: var(--np-color-tertiary-container); --np-tonal-button-label-text-color: var(--np-color-on-tertiary-container)"
>
{#snippet icon()}<Icon>add</Icon>{/snippet}
<Button variant="tonal">New document</Button>
<Button variant="tonal">New folder</Button>
<Button variant="tonal">Upload</Button>
</FabMenu>
</div>
As link
Give a FAB an href and it renders an <a>. A disabled FAB stays a <button>, because a disabled link is still followable.
<script lang="ts">
import { Fab } from 'noph-ui'
import { Icon } from 'noph-ui/icons'
</script>
<Fab href="/components/button" label="Go to buttons">
{#snippet icon()}<Icon>arrow_forward</Icon>{/snippet}
</Fab>
Theming
| Custom property | Description |
|---|---|
--np-fab-container-color | Background, overriding the variant. |
--np-fab-icon-color | Icon and label color, overriding the variant. |
--np-fab-shape | Corner radius at rest, overriding the shape. |
--np-fab-pressed-shape | Corner radius while pressed. |
--np-fab-elevation | Shadow, overriding lowered. |
API
Fab attributes
A FAB renders a <button>, or an <a> with an href, and takes that element's attributes. bind:element gives you whichever
it rendered.
| Attribute | Type | Default | Description |
|---|---|---|---|
label | string | undefined | undefined | Accessible name and tooltip text. A FAB shows no text, so set it. |
icon | Snippet | undefined | undefined | The icon. |
variant | 'primary' | 'secondary' | 'tertiary' | 'primary-container' | 'secondary-container' |
'tertiary-container' | 'primary-container' | Color style, named after the tokens it maps to. |
size | 's' | 'm' | 'l' | 's' | 56, 80 or 96 pixels. |
shape | 'round' | 'square' | 'round' | Corner radius at rest. |
lowered | boolean | false | Drops the shadow a level. |
disabled | boolean | null | undefined | false | Makes the FAB non-interactive and forces a <button>. |
ExtendedFab attributes
Everything Fab takes, with label shown as text rather than used as a tooltip,
plus:
| Attribute | Type | Default | Description |
|---|---|---|---|
collapsed | boolean | false | Shrinks to the icon alone, animating the width. The label moves to aria-label. |