UIPackage
Menu

Fab

fab ui
Edit on GitHub

Floating action button — a fixed or absolute positioned circular button for the primary screen action. Supports an icon (default), an extended label variant, mini/large sizes, four color variants, six anchor positions, and a disabled state.

Also available for Vue ->

Installation

$ npx shadcn@latest add https://uipkge.dev/r/react/fab.json
Named registry: npx shadcn@latest add @uipkge-react/fab Installs to: components/ui/fab/

Examples

Props

Name Type / Values Default Required
variant
'default''secondary''destructive''outline'
default optional
size
'mini''default''large''extended'
default optional
position
'bottom-right''bottom-left''top-right''top-left''bottom-center''inline'
bottom-right optional
label

Label text — renders an extended FAB. Use children for the icon.

string optional
asChild

emitting a <button> — the React equivalent of reka-ui's as-child.

boolean optional
absolute

Use absolute instead of fixed positioning (for contained FABs).

boolean optional
ariaLabel

Accessible label. Defaults to the label prop or 'Floating action'.

string optional

Used by

Files installed (3)

  • components/ui/fab/Fab.tsx 1.9 kB
    import * as React from 'react'
    import { Slot } from '@radix-ui/react-slot'
    import { cn } from '@/lib/utils'
    import { fabVariants, type FabVariants } from './fab.variants'
    
    export interface FabProps
      extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'aria-label'>,
        FabVariants {
      /** Label text — renders an extended FAB. Use children for the icon. */
      label?: string
      /** Render the child element as the FAB (merging props/styles) instead of
       *  emitting a <button> — the React equivalent of reka-ui's as-child. */
      asChild?: boolean
      /** Use absolute instead of fixed positioning (for contained FABs). */
      absolute?: boolean
      /** Accessible label. Defaults to the label prop or 'Floating action'. */
      ariaLabel?: string
    }
    
    const Fab = React.forwardRef<HTMLButtonElement, FabProps>(
      (
        {
          className,
          label,
          asChild = false,
          variant,
          size,
          position,
          absolute = false,
          disabled,
          ariaLabel,
          onClick,
          children,
          ...props
        },
        ref,
      ) => {
        const Comp = asChild ? Slot : 'button'
        const resolvedSize = label ? 'extended' : size
        return (
          <Comp
            data-uipkge=""
            data-slot="fab"
            data-variant={variant ?? undefined}
            data-size={resolvedSize ?? undefined}
            data-position={position ?? undefined}
            disabled={disabled}
            aria-label={ariaLabel || label || 'Floating action'}
            className={cn(
              fabVariants({ variant, size: resolvedSize, position }),
              absolute && position !== 'inline' && 'absolute',
              className,
            )}
            onClick={(e) => {
              if (disabled) return
              onClick?.(e)
            }}
            ref={ref}
            {...props}
          >
            {children}
            {label ? <span className="pr-1">{label}</span> : null}
          </Comp>
        )
      },
    )
    Fab.displayName = 'Fab'
    
    export { Fab }
  • components/ui/fab/fab.variants.ts 1.6 kB
    import type { VariantProps } from 'class-variance-authority'
    import { cva } from 'class-variance-authority'
    
    export const fabVariants = cva(
      "inline-flex items-center justify-center gap-2 rounded-full font-medium shadow-lg transition-[color,background-color,box-shadow,transform] duration-200 outline-none focus-visible:ring-ring/50 focus-visible:ring-[3px] active:scale-95 touch-manipulation [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-6 disabled:pointer-events-none disabled:opacity-50",
      {
        variants: {
          variant: {
            default: 'bg-primary text-primary-foreground hover:bg-primary/90',
            secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
            destructive: 'bg-destructive text-white hover:bg-destructive/90',
            outline:
              'border bg-background text-foreground hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50',
          },
          size: {
            mini: "size-10 [&_svg:not([class*='size-'])]:size-4",
            default: 'size-14',
            large: "size-16 [&_svg:not([class*='size-'])]:size-7",
            extended: 'h-14 px-5',
          },
          position: {
            'bottom-right': 'fixed bottom-6 right-6',
            'bottom-left': 'fixed bottom-6 left-6',
            'top-right': 'fixed top-6 right-6',
            'top-left': 'fixed top-6 left-6',
            'bottom-center': 'fixed bottom-6 left-1/2 -translate-x-1/2',
            inline: '',
          },
        },
        defaultVariants: {
          variant: 'default',
          size: 'default',
          position: 'bottom-right',
        },
      },
    )
    
    export type FabVariants = VariantProps<typeof fabVariants>
  • components/ui/fab/index.ts 0.1 kB
    export { Fab, type FabProps } from './Fab'
    export { fabVariants, type FabVariants } from './fab.variants'

Raw manifest: https://uipkge.dev/r/react/fab.json