Files
sigpro-ui/docs/components/fab.md
2026-04-06 03:19:15 +02:00

13 KiB
Raw Blame History

Fab

Floating Action Button (FAB) component for primary actions with expandable menu options.

Tag

Fab

Props

Prop Type Default Description
icon string | VNode | Signal - Main FAB icon
label string | VNode | Signal - Text label for main button
actions Array<Action> | Signal<Array> [] Array of action buttons that expand from FAB
position string 'bottom-6 right-6' CSS position classes (e.g., 'bottom-6 left-6')
class string '' Additional CSS classes (DaisyUI + Tailwind)

Action Structure

Property Type Description
label string | VNode Label text shown next to action button
icon string | VNode Icon for the action button
onclick function Click handler
class string Additional CSS classes for the action button
text string Alternative text when no icon is provided

Styling

Fab uses daisyUI Button classes for styling the main button and action buttons:

Category Keywords Description
Color btn-primary, btn-secondary, btn-accent, btn-info, btn-success, btn-warning, btn-error Visual color variants
Size btn-xs, btn-sm, btn-md, btn-lg, btn-xl Button scale
Shape btn-circle Circular button shape (default for FAB)

For further details, check the daisyUI FAB Documentation Full reference for CSS classes.

Example

Fab({
  icon: "",
  class: "btn-primary btn-lg",
  position: "bottom-6 right-6",
  actions: [
    { icon: "📝", label: "New Note", onclick: () => console.log("Create note") }
  ]
});

Live Examples

Basic FAB

Live Demo

const BasicDemo = () => {
  return Div({ class: 'relative h-[300px] w-full bg-base-100 rounded-lg overflow-hidden' }, [
    Fab({
      icon: '',
      actions: [
        { icon: '📝', label: 'New Note', onclick: () => Toast('Create note', 'alert-info', 2000) },
        { icon: '📷', label: 'Take Photo', onclick: () => Toast('Open camera', 'alert-info', 2000) },
        { icon: '📎', label: 'Attach File', onclick: () => Toast('Attach file', 'alert-info', 2000) }
      ]
    })
  ]);
};
Mount(BasicDemo, '#demo-basic');

With Label

Live Demo

const LabelDemo = () => {
  return Div({ class: 'relative h-[300px] w-full bg-base-100 rounded-lg overflow-hidden' }, [
    Fab({
      label: 'Create',
      icon: '✨',
      actions: [
        { icon: '📝', label: 'Document', onclick: () => Toast('New document', 'alert-success', 2000) },
        { icon: '🎨', label: 'Design', onclick: () => Toast('New design', 'alert-success', 2000) },
        { icon: '📊', label: 'Spreadsheet', onclick: () => Toast('New spreadsheet', 'alert-success', 2000) }
      ]
    })
  ]);
};
Mount(LabelDemo, '#demo-label');

Different Positions

Live Demo

const PositionsDemo = () => {
  const position = $('bottom-6 right-6');
  
  return Div({ class: 'relative h-[500px] w-full bg-base-100 rounded-lg overflow-hidden' }, [
    Div({ class: 'absolute top-4 left-4 z-20 bg-base-200 p-2 rounded-lg shadow' }, [
      Select({
        items: [
          { value: 'bottom-6 right-6', label: 'Bottom Right' },
          { value: 'bottom-6 left-6', label: 'Bottom Left' },
          { value: 'top-6 right-6', label: 'Top Right' },
          { value: 'top-6 left-6', label: 'Top Left' }
        ],
        value: position,
        onchange: (e) => position(e.target.value)
      })
    ]),
    Div({ class: 'absolute inset-0 flex items-center justify-center text-sm opacity-50 pointer-events-none' }, [
      'FAB position changes relative to this container'
    ]),
    Fab({
      position: () => position(),
      icon: '🧭',
      actions: [
        { icon: '⬅️', label: 'Bottom Left', onclick: () => position('bottom-6 left-6') },
        { icon: '➡️', label: 'Bottom Right', onclick: () => position('bottom-6 right-6') },
        { icon: '⬆️', label: 'Top Right', onclick: () => position('top-6 right-6') },
        { icon: '⬇️', label: 'Top Left', onclick: () => position('top-6 left-6') }
      ]
    })
  ]);
};
Mount(PositionsDemo, '#demo-positions');

Color Variants

Live Demo

const ColorsDemo = () => {
  const variant = $('primary');
  
  const variants = {
    primary: { class: 'btn-primary', icon: '🔵' },
    secondary: { class: 'btn-secondary', icon: '🟣' },
    accent: { class: 'btn-accent', icon: '🔴' },
    info: { class: 'btn-info', icon: '🔷' },
    success: { class: 'btn-success', icon: '🟢' },
    warning: { class: 'btn-warning', icon: '🟡' },
    error: { class: 'btn-error', icon: '🔴' }
  };
  
  return Div({ class: 'relative h-[300px] w-full bg-base-100 rounded-lg overflow-hidden' }, [
    Div({ class: 'absolute top-4 left-4 z-20 bg-base-200 p-2 rounded-lg shadow' }, [
      Select({
        items: Object.keys(variants).map(v => ({ value: v, label: v.charAt(0).toUpperCase() + v.slice(1) })),
        value: variant,
        onchange: (e) => variant(e.target.value)
      })
    ]),
    Fab({
      class: variants[variant()].class,
      icon: variants[variant()].icon,
      actions: [
        { icon: '📝', label: 'Action 1', onclick: () => Toast('Action 1', 'alert-info', 2000) },
        { icon: '🎨', label: 'Action 2', onclick: () => Toast('Action 2', 'alert-info', 2000) },
        { icon: '⚙️', label: 'Action 3', onclick: () => Toast('Action 3', 'alert-info', 2000) }
      ]
    })
  ]);
};
Mount(ColorsDemo, '#demo-colors');

Reactive Actions

Live Demo

const ReactiveActions = () => {
  const count = $(0);
  
  const actions = () => [
    { 
      icon: '🔢', 
      label: `Count: ${count()}`, 
      onclick: () => {} 
    },
    { 
      icon: '', 
      label: 'Increment', 
      onclick: () => count(count() + 1) 
    },
    { 
      icon: '', 
      label: 'Decrement', 
      onclick: () => count(count() - 1) 
    },
    { 
      icon: '🔄', 
      label: 'Reset', 
      onclick: () => count(0) 
    }
  ];
  
  return Div({ class: 'relative h-[300px] w-full bg-base-100 rounded-lg overflow-hidden' }, [
    Fab({
      icon: () => count() > 0 ? `🔢 ${count()}` : '🎛️',
      actions: actions
    })
  ]);
};
Mount(ReactiveActions, '#demo-reactive');

Document Actions

Live Demo

const DocumentActions = () => {
  const saved = $(false);
  
  const handleSave = () => {
    saved(true);
    Toast('Document saved!', 'alert-success', 2000);
    setTimeout(() => saved(false), 3000);
  };
  
  return Div({ class: 'relative h-[300px] w-full bg-base-100 rounded-lg overflow-hidden' }, [
    Div({ class: 'absolute inset-0 flex flex-col items-center justify-center' }, [
      Div({ class: 'text-6xl mb-4' }, '📄'),
      Div({ class: 'text-sm opacity-70' }, 'Untitled Document'),
      () => saved() ? Div({ class: 'mt-4' }, Alert({ type: 'success', message: '✓ Saved successfully' })) : null
    ]),
    Fab({
      icon: '✏️',
      actions: [
        { icon: '💾', label: 'Save', onclick: handleSave },
        { icon: '📋', label: 'Copy', onclick: () => Toast('Copied!', 'alert-info', 2000) },
        { icon: '✂️', label: 'Cut', onclick: () => Toast('Cut!', 'alert-info', 2000) },
        { icon: '📎', label: 'Share', onclick: () => Toast('Share dialog', 'alert-info', 2000) }
      ]
    })
  ]);
};
Mount(DocumentActions, '#demo-document');

Messaging FAB

Live Demo

const MessagingFAB = () => {
  const unread = $(3);
  
  return Div({ class: 'relative h-[300px] w-full bg-base-100 rounded-lg overflow-hidden' }, [
    Div({ class: 'absolute inset-0 flex flex-col items-center justify-center' }, [
      Div({ class: 'text-6xl mb-4' }, '💬'),
      Div({ class: 'text-sm opacity-70' }, 'Messages'),
      () => unread() > 0 ? Div({ class: 'badge badge-error mt-2' }, `${unread()} unread`) : null
    ]),
    Fab({
      icon: () => `💬${unread() > 0 ? ` ${unread()}` : ''}`,
      class: 'btn-primary',
      actions: [
        { 
          icon: '👤', 
          label: 'New Message', 
          onclick: () => Toast('Start new conversation', 'alert-info', 2000) 
        },
        { 
          icon: '👥', 
          label: 'Group Chat', 
          onclick: () => Toast('Create group', 'alert-info', 2000) 
        },
        { 
          icon: '📞', 
          label: 'Voice Call', 
          onclick: () => Toast('Start call', 'alert-info', 2000) 
        },
        { 
          icon: '📹', 
          label: 'Video Call', 
          onclick: () => Toast('Start video call', 'alert-info', 2000) 
        },
        { 
          icon: '🔔', 
          label: () => `Mark as read (${unread()})`, 
          onclick: () => {
            unread(0);
            Toast('All messages read', 'alert-success', 2000);
          } 
        }
      ]
    })
  ]);
};
Mount(MessagingFAB, '#demo-messaging');

All Variants

Live Demo

const VariantsDemo = () => {
  const actions = [
    { icon: '⭐', label: 'Favorite', onclick: () => Toast('Favorited', 'alert-info', 2000) },
    { icon: '🔔', label: 'Remind', onclick: () => Toast('Reminder set', 'alert-info', 2000) },
    { icon: '📅', label: 'Schedule', onclick: () => Toast('Scheduled', 'alert-info', 2000) }
  ];
  
  return Div({ class: 'relative h-[400px] w-full bg-base-100 rounded-lg overflow-hidden' }, [
    Div({ class: 'grid grid-cols-2 gap-4 p-4 h-full' }, [
      Div({ class: 'relative border rounded-lg bg-base-200' }, [
        Span({ class: 'absolute top-2 left-2 text-xs opacity-50' }, 'Primary'),
        Fab({ icon: '🔵', class: 'btn-primary', actions, position: 'bottom-6 left-6' })
      ]),
      Div({ class: 'relative border rounded-lg bg-base-200' }, [
        Span({ class: 'absolute top-2 left-2 text-xs opacity-50' }, 'Secondary'),
        Fab({ icon: '🟣', class: 'btn-secondary', actions, position: 'bottom-6 right-6' })
      ]),
      Div({ class: 'relative border rounded-lg bg-base-200' }, [
        Span({ class: 'absolute top-2 left-2 text-xs opacity-50' }, 'Accent'),
        Fab({ icon: '🔴', class: 'btn-accent', actions, position: 'top-6 left-6' })
      ]),
      Div({ class: 'relative border rounded-lg bg-base-200' }, [
        Span({ class: 'absolute top-2 left-2 text-xs opacity-50' }, 'Success'),
        Fab({ icon: '🟢', class: 'btn-success', actions, position: 'top-6 right-6' })
      ])
    ])
  ]);
};
Mount(VariantsDemo, '#demo-variants');