MobTranslate styleguide

Floating Action Button

Promote one primary contextual action while preserving reading space, focus and navigation.

Choose one promoted action

Use a floating action for a frequent creation or other primary contextual task. Keep ordinary navigation, destructive operations and a collection of unrelated actions in their appropriate controls. Prefer an extended visible label when the icon alone is ambiguous.

This is a MobTranslate web equivalent with its own dimensions and tokens. It does not claim to implement Material Expressive motion physics, morphing or every native-platform FAB behavior.

Anatomy and sizes

ModeRendered specificationDecision
Small icon44×44pxCompact target retains the product touch minimum.
Medium icon56×56pxDefault promoted action.
Large icon72×72pxUse only when space and action hierarchy justify it.
ExtendedAuto width; min-height follows size; 20px inline / 12px block paddingVisible label can wrap; do not force translated text into an icon square.
Surface--radius-lg / --shadow-lg / primary rolesUse shared theme/state tokens.
PositionOwned by application layoutComponent itself does not fix to viewport or hide content.

Working creation lab

Local example workspace. The action sits in flow here; application placement must preserve content and focus clearance.

0 example drafts created locally. Nothing was saved or published.

tsx
'use client';
import { useState, useRef } from 'react';
import { FloatingActionButton, TooltipProvider, Tooltip, TooltipTrigger, TooltipPortal, TooltipPositioner, TooltipPopup } from '@mobtranslate/ui';

export function FloatingActionsExample() {
  const portalContainer=useRef<HTMLDivElement>(null);
  const [count, setCount] = useState(0);
  const [extended, setExtended] = useState(true);
  const [size, setSize] = useState<'sm' | 'md' | 'lg'>('md');
  const action=<FloatingActionButton size={size} extended={extended} aria-label="Add example draft" onClick={() => setCount(count + 1)}>
    <svg width="24" height="24" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M5 12h14M12 5v14" stroke="currentColor" strokeWidth="2" fill="none" /></svg>{extended && 'Add example draft'}
  </FloatingActionButton>;
  return <div ref={portalContainer} data-fab-lab className="space-y-4">
    <label className="block">Floating action size<select className="mt-input mt-2" value={size} onChange={event => setSize(event.target.value as typeof size)}>{(['sm', 'md', 'lg'] as const).map(value => <option key={value}>{value}</option>)}</select></label>
    <label className="flex items-center gap-3 min-h-11"><input type="checkbox" checked={extended} onChange={event => setExtended(event.target.checked)} />Show extended action label</label>
    <div className="relative border border-[var(--color-border)] rounded-lg p-4 space-y-6">
      <p>Local example workspace. The action sits in flow here; application placement must preserve content and focus clearance.</p>
      <div className="flex justify-end"><TooltipProvider><Tooltip disabled={extended}><TooltipTrigger render={action} /><TooltipPortal container={portalContainer}><TooltipPositioner sideOffset={8}><TooltipPopup>Create an example draft locally.</TooltipPopup></TooltipPositioner></TooltipPortal></Tooltip></TooltipProvider></div>
    </div>
    <p role="status">{count} example {count === 1 ? 'draft' : 'drafts'} created locally. Nothing was saved or published.</p>
  </div>;
}

Placement and adaptation

  • Prefer in-flow or a reserved action region when reading content needs unobstructed access. A viewport-fixed action requires a deliberate content-clearance contract.
  • Use logical positioning and account for safe-area insets and on-screen keyboards. Test both directions rather than assuming bottom-right is universal.
  • Reserve space for bottom navigation, consent banners, toasts and focused controls. Do not place all overlays in the same corner.
  • When space is limited, choose a visible in-flow action rather than hiding its label or obscuring source citations.
  • Keep DOM/focus order logical; visual floating position does not justify moving the action ahead of essential instructions.

API reference

PropContract
sizesm | md | lg; md default
extendedboolean; false. Extended mode supplies visible label content.
aria-labelRequired for icon-only mode; supply an accurate action name.
children / leftIconIcon and optional visible extended label
variantButton variants; primary default
typebutton default; submit/reset explicit
disabled / loading / loadingTextSame behavior as Button; task status remains application-owned
className / style / native propsPassed to the native action; layout can add placement rules
asChild / fullWidthExcluded; application placement and navigation are separate concerns
refRef<HTMLElement> to the native button

Behavior and accessibility

  • Use a real button for an action and a link for navigation. Visible labels and accessible names must identify the same task.
  • Native buttons activate with Enter and Space; ordinary disabled buttons leave the tab order. Do not rely on a spinner as the only pending announcement.
  • Report pending, completion, cancellation and failure with task-specific status text. A local animation is not proof that a request completed.
  • Retain a meaningful focus destination when a pending button becomes disabled or disappears. The lab returns focus after completion or cancellation.
  • Focus, meaningful boundaries and icons need their own contrast checks. Text-pair measurements alone do not certify a complete component.
  • Respect reduced motion and forced colors. Do not obscure focus with a floating control or sticky header.

Failure cases

  • Avoid a floating delete/publish action without clear consequence and workflow safeguards.
  • Do not add several competing floating actions or use a plus symbol for an unrelated task.
  • Do not hide permission, attribution or recovery content beneath the action.
  • A local draft count is not a persisted draft or a published entry. Verify the real outcome when connecting a backend.

Verification

  • Toggle extended/icon-only mode, select all sizes and activate using keyboard/pointer. The local count and status must agree.
  • Measure 44/56/72px icon targets and check the extended label at narrow width.
  • Test fixed placement in the real consuming layout with zoom, RTL, safe areas, on-screen keyboard and bottom overlays.
  • Inspect focus, disabled and pending behavior in both themes and reduced-motion/forced-colors modes.