Files
sigpro-ui/docs/components/drawer.md
2026-04-03 01:41:07 +02:00

15 KiB
Raw Blame History

Drawer

Drawer component for creating off-canvas side panels with overlay and toggle functionality.

Tag

Drawer

Props

Prop Type Default Description
id string Required Unique identifier for the drawer
open boolean | Signal<boolean> false Drawer open state
side VNode Required Content to display in the drawer panel
content VNode Required Main page content
class string '' Additional CSS classes (DaisyUI + Tailwind)

Styling

Drawer supports all daisyUI Drawer classes:

Category Keywords Description
Position drawer-end Drawer opens from the right side
Width w-64, w-80, w-96 Custom drawer width (Tailwind)

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

Live Examples

Basic Drawer

Live Demo

const BasicDemo = () => {
  const isOpen = $(false);
  
  return Drawer({
    id: 'basic-drawer',
    open: isOpen,
    side: Div({ class: 'p-4' }, [
      Div({ class: 'text-lg font-bold mb-4' }, 'Menu'),
      Div({ class: 'flex flex-col gap-2' }, [
        Button({ class: 'btn btn-ghost justify-start' }, 'Home'),
        Button({ class: 'btn btn-ghost justify-start' }, 'About'),
        Button({ class: 'btn btn-ghost justify-start' }, 'Contact')
      ])
    ]),
    content: Div({ class: 'p-4 text-center' }, [
      Button({ 
        class: 'btn btn-primary',
        onclick: () => isOpen(true)
      }, 'Open Drawer')
    ])
  });
};
$mount(BasicDemo, '#demo-basic');

Navigation Drawer

Live Demo

const NavDrawer = () => {
  const isOpen = $(false);
  const activePage = $('home');
  
  const pages = {
    home: 'Welcome to the Home Page!',
    about: 'About Us - Learn more about our company',
    services: 'Our Services - What we offer',
    contact: 'Contact Us - Get in touch'
  };
  
  return Drawer({
    id: 'nav-drawer',
    open: isOpen,
    side: Div({ class: 'p-4 w-64' }, [
      Div({ class: 'text-xl font-bold mb-6' }, 'MyApp'),
      Div({ class: 'flex flex-col gap-1' }, [
        Button({ 
          class: `btn btn-ghost justify-start ${activePage() === 'home' ? 'btn-active' : ''}`,
          onclick: () => {
            activePage('home');
            isOpen(false);
          }
        }, '🏠 Home'),
        Button({ 
          class: `btn btn-ghost justify-start ${activePage() === 'about' ? 'btn-active' : ''}`,
          onclick: () => {
            activePage('about');
            isOpen(false);
          }
        }, ' About'),
        Button({ 
          class: `btn btn-ghost justify-start ${activePage() === 'services' ? 'btn-active' : ''}`,
          onclick: () => {
            activePage('services');
            isOpen(false);
          }
        }, '⚙️ Services'),
        Button({ 
          class: `btn btn-ghost justify-start ${activePage() === 'contact' ? 'btn-active' : ''}`,
          onclick: () => {
            activePage('contact');
            isOpen(false);
          }
        }, '📧 Contact')
      ])
    ]),
    content: Div({ class: 'p-4' }, [
      Div({ class: 'flex justify-between items-center mb-4' }, [
        Button({ 
          class: 'btn btn-ghost btn-circle',
          onclick: () => isOpen(true)
        }, '☰'),
        Span({ class: 'text-lg font-bold' }, 'MyApp')
      ]),
      Div({ class: 'card bg-base-200 shadow-lg' }, [
        Div({ class: 'card-body' }, [
          Div({ class: 'text-2xl font-bold mb-2' }, () => activePage().charAt(0).toUpperCase() + activePage().slice(1)),
          Div({ class: 'text-lg' }, () => pages[activePage()])
        ])
      ])
    ])
  });
};
$mount(NavDrawer, '#demo-nav');

Settings Drawer

Live Demo

const SettingsDrawer = () => {
  const isOpen = $(false);
  const darkMode = $(false);
  const notifications = $(true);
  const autoSave = $(false);
  
  return Drawer({
    id: 'settings-drawer',
    open: isOpen,
    side: Div({ class: 'p-4 w-80' }, [
      Div({ class: 'flex justify-between items-center mb-6' }, [
        Span({ class: 'text-xl font-bold' }, 'Settings'),
        Button({ 
          class: 'btn btn-ghost btn-circle btn-sm',
          onclick: () => isOpen(false)
        }, '✕')
      ]),
      Div({ class: 'flex flex-col gap-4' }, [
        Div({ class: 'flex justify-between items-center' }, [
          Span({}, 'Dark Mode'),
          Swap({
            value: darkMode,
            on: "🌙",
            off: "☀️",
            onclick: () => darkMode(!darkMode())
          })
        ]),
        Div({ class: 'flex justify-between items-center' }, [
          Span({}, 'Notifications'),
          Swap({
            value: notifications,
            on: "🔔",
            off: "🔕",
            onclick: () => notifications(!notifications())
          })
        ]),
        Div({ class: 'flex justify-between items-center' }, [
          Span({}, 'Auto Save'),
          Swap({
            value: autoSave,
            on: "✅",
            off: "⭕",
            onclick: () => autoSave(!autoSave())
          })
        ])
      ]),
      Div({ class: 'divider my-4' }),
      Div({ class: 'flex gap-2' }, [
        Button({ 
          class: 'btn btn-primary flex-1',
          onclick: () => {
            isOpen(false);
            Toast('Settings saved!', 'alert-success', 2000);
          }
        }, 'Save'),
        Button({ 
          class: 'btn btn-ghost flex-1',
          onclick: () => isOpen(false)
        }, 'Cancel')
      ])
    ]),
    content: Div({ class: 'p-4' }, [
      Div({ class: 'flex justify-between items-center' }, [
        Span({ class: 'text-lg font-bold' }, 'Dashboard'),
        Button({ 
          class: 'btn btn-ghost btn-circle',
          onclick: () => isOpen(true)
        }, '⚙️')
      ]),
      Div({ class: 'mt-4 grid grid-cols-2 gap-4' }, [
        Div({ class: 'stat bg-base-200 rounded-lg p-4' }, [
          Div({ class: 'stat-title' }, 'Users'),
          Div({ class: 'stat-value' }, '1,234')
        ]),
        Div({ class: 'stat bg-base-200 rounded-lg p-4' }, [
          Div({ class: 'stat-title' }, 'Revenue'),
          Div({ class: 'stat-value' }, '$45K')
        ])
      ])
    ])
  });
};
$mount(SettingsDrawer, '#demo-settings');

Cart Drawer

Live Demo

const CartDrawer = () => {
  const isOpen = $(false);
  const cart = $([
    { id: 1, name: 'Product 1', price: 29, quantity: 2 },
    { id: 2, name: 'Product 2', price: 49, quantity: 1 }
  ]);
  
  const updateQuantity = (id, delta) => {
    cart(cart().map(item => {
      if (item.id === id) {
        const newQty = Math.max(0, item.quantity + delta);
        return newQty === 0 ? null : { ...item, quantity: newQty };
      }
      return item;
    }).filter(Boolean));
  };
  
  const total = () => cart().reduce((sum, item) => sum + (item.price * item.quantity), 0);
  
  return Drawer({
    id: 'cart-drawer',
    open: isOpen,
    side: Div({ class: 'flex flex-col h-full' }, [
      Div({ class: 'p-4 border-b border-base-300' }, [
        Div({ class: 'flex justify-between items-center' }, [
          Span({ class: 'text-xl font-bold' }, `Cart (${cart().length} items)`),
          Button({ 
            class: 'btn btn-ghost btn-circle btn-sm',
            onclick: () => isOpen(false)
          }, '✕')
        ])
      ]),
      Div({ class: 'flex-1 overflow-y-auto p-4' }, cart().length === 0 
        ? Div({ class: 'text-center text-gray-500 mt-8' }, 'Your cart is empty')
        : Div({ class: 'flex flex-col gap-3' }, cart().map(item =>
          Div({ class: 'flex gap-3 items-center p-2 bg-base-200 rounded-lg' }, [
            Div({ class: 'flex-1' }, [
              Div({ class: 'font-medium' }, item.name),
              Div({ class: 'text-sm' }, `$${item.price} each`)
            ]),
            Div({ class: 'flex items-center gap-2' }, [
              Button({ 
                class: 'btn btn-xs btn-circle',
                onclick: () => updateQuantity(item.id, -1)
              }, '-'),
              Span({ class: 'w-8 text-center' }, item.quantity),
              Button({ 
                class: 'btn btn-xs btn-circle',
                onclick: () => updateQuantity(item.id, 1)
              }, '+')
            ]),
            Span({ class: 'font-bold w-16 text-right' }, `$${item.price * item.quantity}`)
          ])
        ))
      ),
      Div({ class: 'p-4 border-t border-base-300' }, [
        Div({ class: 'flex justify-between items-center mb-4' }, [
          Span({ class: 'font-bold' }, 'Total'),
          Span({ class: 'text-xl font-bold' }, () => `$${total()}`)
        ]),
        Button({ 
          class: 'btn btn-primary w-full',
          onclick: () => {
            isOpen(false);
            Toast('Checkout initiated!', 'alert-success', 2000);
          },
          disabled: () => cart().length === 0
        }, 'Checkout')
      ])
    ]),
    content: Div({ class: 'p-4' }, [
      Div({ class: 'flex justify-between items-center' }, [
        Span({ class: 'text-lg font-bold' }, 'Store'),
        Button({ 
          class: 'btn btn-primary',
          onclick: () => isOpen(true)
        }, () => `🛒 Cart (${cart().length})`)
      ]),
      Div({ class: 'mt-4 grid grid-cols-2 gap-4' }, [
        Button({ 
          class: 'btn btn-outline h-32 flex flex-col',
          onclick: () => {
            cart([...cart(), { id: Date.now(), name: 'New Product', price: 39, quantity: 1 }]);
            Toast('Added to cart!', 'alert-success', 1500);
          }
        }, ['📦', 'Add to Cart'])
      ])
    ])
  });
};
$mount(CartDrawer, '#demo-cart');

Responsive Drawer

Live Demo

const ResponsiveDrawer = () => {
  const isOpen = $(false);
  const activePage = $('home');
  
  const MenuItems = () => Div({ class: 'flex flex-col gap-1 p-4' }, [
    Button({ 
      class: `btn btn-ghost justify-start ${activePage() === 'home' ? 'btn-active' : ''}`,
      onclick: () => {
        activePage('home');
        if (window.innerWidth < 1024) isOpen(false);
      }
    }, '🏠 Home'),
    Button({ 
      class: `btn btn-ghost justify-start ${activePage() === 'analytics' ? 'btn-active' : ''}`,
      onclick: () => {
        activePage('analytics');
        if (window.innerWidth < 1024) isOpen(false);
      }
    }, '📊 Analytics'),
    Button({ 
      class: `btn btn-ghost justify-start ${activePage() === 'settings' ? 'btn-active' : ''}`,
      onclick: () => {
        activePage('settings');
        if (window.innerWidth < 1024) isOpen(false);
      }
    }, '⚙️ Settings')
  ]);
  
  return Drawer({
    id: 'responsive-drawer',
    open: isOpen,
    side: Div({ class: 'w-64' }, [
      Div({ class: 'text-xl font-bold p-4 border-b border-base-300' }, 'Menu'),
      MenuItems()
    ]),
    content: Div({ class: 'flex' }, [
      Div({ class: 'hidden lg:block w-64 border-r border-base-300' }, [MenuItems()]),
      Div({ class: 'flex-1 p-4' }, [
        Div({ class: 'flex justify-between items-center lg:hidden mb-4' }, [
          Button({ 
            class: 'btn btn-ghost btn-circle',
            onclick: () => isOpen(true)
          }, '☰'),
          Span({ class: 'text-lg font-bold' }, 'MyApp')
        ]),
        Div({ class: 'card bg-base-200' }, [
          Div({ class: 'card-body' }, [
            Div({ class: 'text-2xl font-bold' }, () => activePage().charAt(0).toUpperCase() + activePage().slice(1)),
            Div({}, 'Content area. On desktop, the menu is always visible on the left.')
          ])
        ])
      ])
    ])
  });
};
$mount(ResponsiveDrawer, '#demo-responsive');

Form Drawer

Live Demo

const FormDrawer = () => {
  const isOpen = $(false);
  const name = $('');
  const email = $('');
  const message = $('');
  
  const handleSubmit = () => {
    if (name() && email() && message()) {
      Toast('Message sent!', 'alert-success', 2000);
      isOpen(false);
      name('');
      email('');
      message('');
    } else {
      Toast('Please fill all fields', 'alert-warning', 2000);
    }
  };
  
  return Drawer({
    id: 'form-drawer',
    open: isOpen,
    side: Div({ class: 'p-4 w-96' }, [
      Div({ class: 'flex justify-between items-center mb-4' }, [
        Span({ class: 'text-xl font-bold' }, 'Contact Us'),
        Button({ 
          class: 'btn btn-ghost btn-circle btn-sm',
          onclick: () => isOpen(false)
        }, '✕')
      ]),
      Div({ class: 'flex flex-col gap-4' }, [
        Input({
          label: 'Name',
          value: name,
          placeholder: 'Your name',
          oninput: (e) => name(e.target.value)
        }),
        Input({
          label: 'Email',
          type: 'email',
          value: email,
          placeholder: 'your@email.com',
          oninput: (e) => email(e.target.value)
        }),
        Div({ class: 'form-control' }, [
          Span({ class: 'label-text mb-1' }, 'Message'),
          $html('textarea', {
            class: 'textarea textarea-bordered h-24',
            placeholder: 'Your message',
            value: message,
            oninput: (e) => message(e.target.value)
          })
        ]),
        Div({ class: 'flex gap-2 mt-2' }, [
          Button({ 
            class: 'btn btn-primary flex-1',
            onclick: handleSubmit
          }, 'Send'),
          Button({ 
            class: 'btn btn-ghost flex-1',
            onclick: () => isOpen(false)
          }, 'Cancel')
        ])
      ])
    ]),
    content: Div({ class: 'p-4 text-center' }, [
      Button({ 
        class: 'btn btn-primary',
        onclick: () => isOpen(true)
      }, 'Contact Us')
    ])
  });
};
$mount(FormDrawer, '#demo-form');