Slideover

Panel overlays that slide from screen edges, maintaining spatial context for filters, forms, and navigation

Overview

Slideovers are panel overlays that slide in from the edge of the screen, providing contextual information or actions without completely obscuring the main content. Unlike modals which appear in the center, slideovers maintain spatial context and are ideal for secondary tasks, filters, or navigation.

Key Features

  • Four directional positions: left, right, top, bottom
  • Multiple size variants (sm, md, lg, xl, full) or custom sizes
  • Semi-transparent backdrop with optional click-to-close
  • Smooth slide animations from edges
  • Keyboard navigation with Escape key
  • Factory method for dynamic creation
  • Form blueprint integration support
  • Event callbacks for lifecycle management

When to Use Slideovers

  • Filters & Settings: Advanced filters, configuration panels, preferences
  • Detail Views: User profiles, product details, metadata panels
  • Forms: Quick edits, creation forms, data entry without leaving context
  • Navigation: Mobile menus, navigation panels, table of contents
  • Shopping Carts: Cart summary, checkout panels
  • Notifications: Activity feeds, notification panels

Basic Usage

// Factory method (recommended)
const slideover = Domma.elements.slideover({
    title: 'My Slideover',
    content: '<p>Slideover content goes here.</p>',
    position: 'right',  // 'left', 'right', 'top', 'bottom'
    size: 'lg',         // 'sm', 'md', 'lg', 'xl', 'full', or custom (e.g., '400px')
    backdrop: true,
    backdropClose: true,
    keyboard: true
});

// Open the slideover
slideover.open();

// Control methods
slideover.close();
slideover.toggle();
slideover.isOpen();
slideover.setTitle('New Title');
slideover.setContent('<p>Updated content</p>');
slideover.setSize('xl');
slideover.setPosition('left');

HTML Structure (Existing Element)

<div id="my-slideover">
    <div class="dm-slideover-header">
        <h5 class="dm-slideover-title">Slideover Title</h5>
        <button class="dm-slideover-close" data-dismiss="slideover">×</button>
    </div>
    <div class="dm-slideover-body">
        Slideover content goes here.
    </div>
</div>

<script>
const slideover = Domma.elements.slideover('#my-slideover', {
    position: 'right',
    size: 'lg'
});

slideover.open();
</script>

Position Variants

Slideovers can slide in from any edge of the screen. Choose the position that best fits your layout and user workflow.

Position Variants
<div class="demo-grid"><button type="button" class="btn btn-primary" data-action="1">
        <span data-icon="arrow-left" data-icon-size="16"></span> Right (Default)
    </button>
    <button type="button" class="btn btn-primary" data-action="2">
        <span data-icon="arrow-right" data-icon-size="16"></span> Left
    </button>
    <button type="button" class="btn btn-primary" data-action="3">
        <span data-icon="arrow-down" data-icon-size="16"></span> Top
    </button>
    <button type="button" class="btn btn-primary" data-action="4">
        <span data-icon="arrow-up" data-icon-size="16"></span> Bottom
    </button>
</div>
/**
 * Position Variants - from public/showcase/elements/slideover.
 */
export function mount(root) {
    let currentSlideover = null;
      // Position demos
    function demoPositionRight() {
        currentSlideover = E.slideover({
          title: 'Right Slideover',
          content: '<p>This slideover slides in from the right side of the screen.</p><p>This is the default position and works well for detail panels, filters, and forms.</p>',
          position: 'right',
          size: 'lg'
        });
        currentSlideover.open();
      }
    function demoPositionLeft() {
        currentSlideover = E.slideover({
          title: 'Left Slideover',
          content: '<p>This slideover slides in from the left side of the screen.</p><p>Great for navigation menus and table of contents.</p>',
          position: 'left',
          size: 'md'
        });
        currentSlideover.open();
      }
    function demoPositionTop() {
        currentSlideover = E.slideover({
          title: 'Top Slideover',
          content: '<p>This slideover slides down from the top of the screen.</p><p>Perfect for notification panels or headers.</p>',
          position: 'top',
          size: 'sm'
        });
        currentSlideover.open();
      }
    function demoPositionBottom() {
        currentSlideover = E.slideover({
          title: 'Bottom Slideover',
          content: '<p>This slideover slides up from the bottom of the screen.</p><p>Ideal for shopping carts or action sheets.</p>',
          position: 'bottom',
          size: 'md'
        });
        currentSlideover.open();
      }

    // Handlers the old page had inline (onclick=…), wired here.
    $(root).find('[data-action="1"]').on('click', function (event) {
        demoPositionRight();
    });
    $(root).find('[data-action="2"]').on('click', function (event) {
        demoPositionLeft();
    });
    $(root).find('[data-action="3"]').on('click', function (event) {
        demoPositionTop();
    });
    $(root).find('[data-action="4"]').on('click', function (event) {
        demoPositionBottom();
    });
}
// Right (default)
const slideoverRight = Domma.elements.slideover({
    title: 'Right Slideover',
    content: '<p>Slides in from the right side.</p>',
    position: 'right'
});

// Left
const slideoverLeft = Domma.elements.slideover({
    title: 'Left Slideover',
    content: '<p>Slides in from the left side.</p>',
    position: 'left'
});

// Top
const slideoverTop = Domma.elements.slideover({
    title: 'Top Slideover',
    content: '<p>Slides down from the top.</p>',
    position: 'top'
});

// Bottom
const slideoverBottom = Domma.elements.slideover({
    title: 'Bottom Slideover',
    content: '<p>Slides up from the bottom.</p>',
    position: 'bottom'
});

Size Variants

Control the width (for left/right) or height (for top/bottom) using predefined sizes or custom values.

Size Variants
<div class="demo-grid"><button type="button" class="btn btn-secondary" data-action="1">Small (25%)</button>
    <button type="button" class="btn btn-secondary" data-action="2">Medium (50%)</button>
    <button type="button" class="btn btn-secondary" data-action="3">Large (75%)</button>
    <button type="button" class="btn btn-secondary" data-action="4">XL (90%)</button>
    <button type="button" class="btn btn-secondary" data-action="5">Full (100%)</button>
    <button type="button" class="btn btn-secondary" data-action="6">Custom (400px)</button>
</div>
/**
 * Size Variants - from public/showcase/elements/slideover.
 */
export function mount(root) {
    let currentSlideover = null;
      // Size demos
    function demoSizeSmall() {
        currentSlideover = E.slideover({
          title: 'Small Slideover (25%)',
          content: '<p>This is a small slideover, taking up 25% of the screen width.</p>',
          size: 'sm'
        });
        currentSlideover.open();
      }
    function demoSizeMedium() {
        currentSlideover = E.slideover({
          title: 'Medium Slideover (50%)',
          content: '<p>This is a medium slideover, taking up 50% of the screen width.</p>',
          size: 'md'
        });
        currentSlideover.open();
      }
    function demoSizeLarge() {
        currentSlideover = E.slideover({
          title: 'Large Slideover (75%)',
          content: '<p>This is a large slideover, taking up 75% of the screen width.</p>',
          size: 'lg'
        });
        currentSlideover.open();
      }
    function demoSizeXL() {
        currentSlideover = E.slideover({
          title: 'Extra Large Slideover (90%)',
          content: '<p>This is an extra large slideover, taking up 90% of the screen width.</p>',
          size: 'xl'
        });
        currentSlideover.open();
      }
    function demoSizeFull() {
        currentSlideover = E.slideover({
          title: 'Full Slideover (100%)',
          content: '<p>This is a full slideover, taking up 100% of the screen width.</p><p>Acts like a full-screen panel.</p>',
          size: 'full'
        });
        currentSlideover.open();
      }
    function demoSizeCustom() {
        currentSlideover = E.slideover({
          title: 'Custom Size (400px)',
          content: '<p>This slideover has a custom width of exactly 400 pixels.</p><p>You can use px, rem, em, or % for custom sizes.</p>',
          size: '400px'
        });
        currentSlideover.open();
      }

    // Handlers the old page had inline (onclick=…), wired here.
    $(root).find('[data-action="1"]').on('click', function (event) {
        demoSizeSmall();
    });
    $(root).find('[data-action="2"]').on('click', function (event) {
        demoSizeMedium();
    });
    $(root).find('[data-action="3"]').on('click', function (event) {
        demoSizeLarge();
    });
    $(root).find('[data-action="4"]').on('click', function (event) {
        demoSizeXL();
    });
    $(root).find('[data-action="5"]').on('click', function (event) {
        demoSizeFull();
    });
    $(root).find('[data-action="6"]').on('click', function (event) {
        demoSizeCustom();
    });
}
// Predefined sizes
const small = Domma.elements.slideover({
    title: 'Small Slideover',
    content: '<p>25% width</p>',
    size: 'sm'
});

const medium = Domma.elements.slideover({
    title: 'Medium Slideover',
    content: '<p>50% width</p>',
    size: 'md'
});

const large = Domma.elements.slideover({
    title: 'Large Slideover',
    content: '<p>75% width</p>',
    size: 'lg'
});

// Custom size
const custom = Domma.elements.slideover({
    title: 'Custom Slideover',
    content: '<p>400px width</p>',
    size: '400px'  // Can use px, rem, em, %
});

Advanced Features

Backdrop Options

Control backdrop appearance and click behavior.

Backdrop Options
<div class="demo-grid"><button type="button" class="btn btn-outline" data-action="1">No Backdrop</button>
    <button type="button" class="btn btn-outline" data-action="2">Backdrop, No Close</button>
</div>
/**
 * Backdrop Options - from public/showcase/elements/slideover.
 */
export function mount(root) {
    let currentSlideover = null;
      // Advanced features
    function demoNoBackdrop() {
        currentSlideover = E.slideover({
          title: 'No Backdrop',
          content: '<p>This slideover has no backdrop overlay.</p><p>The main content remains fully visible and interactive.</p>',
          backdrop: false
        });
        currentSlideover.open();
      }
    function demoBackdropNoClose() {
        currentSlideover = E.slideover({
          title: 'Backdrop, No Close',
          content: '<p>This slideover has a backdrop but you cannot close it by clicking the backdrop.</p><p>You must use the X button to close.</p>',
          backdrop: true,
          backdropClose: false
        });
        currentSlideover.open();
      }

    // Handlers the old page had inline (onclick=…), wired here.
    $(root).find('[data-action="1"]').on('click', function (event) {
        demoNoBackdrop();
    });
    $(root).find('[data-action="2"]').on('click', function (event) {
        demoBackdropNoClose();
    });
}
// No backdrop
const noBackdrop = Domma.elements.slideover({
    title: 'No Backdrop',
    content: '<p>No overlay behind the slideover.</p>',
    backdrop: false
});

// Backdrop but can't close by clicking it
const backdropNoClose = Domma.elements.slideover({
    title: 'Backdrop, No Close',
    content: '<p>Must use X button to close.</p>',
    backdrop: true,
    backdropClose: false
});

Non-Closable Slideover

Remove the X button and require programmatic closing.

Non-Closable Slideover

const nonClosable = Domma.elements.slideover({
    title: 'Non-Closable',
    content: `
        <p>This slideover has no X button.</p>
        <button onclick="currentSlideover.close()" class="btn">
            Close Programmatically
        </button>
    `,
    closable: false,
    backdropClose: false,
    keyboard: false  // Disable Escape key too
});

Event Callbacks

Hook into slideover lifecycle events.

Test Callbacks

Event Callbacks
<div id="callback-log" class="p-3 bg-gray-100 rounded mb-3" style="min-height: 80px; font-family: monospace; font-size: 0.875rem;"></div>
/**
 * Event Callbacks - from public/showcase/elements/slideover.
 */
export function mount(root) {
    let currentSlideover = null;
      // Position demos
    function demoPositionRight() {
        currentSlideover = E.slideover({
          title: 'Right Slideover',
          content: '<p>This slideover slides in from the right side of the screen.</p><p>This is the default position and works well for detail panels, filters, and forms.</p>',
          position: 'right',
          size: 'lg'
        });
        currentSlideover.open();
      }
    function demoPositionLeft() {
        currentSlideover = E.slideover({
          title: 'Left Slideover',
          content: '<p>This slideover slides in from the left side of the screen.</p><p>Great for navigation menus and table of contents.</p>',
          position: 'left',
          size: 'md'
        });
        currentSlideover.open();
      }
    function demoPositionTop() {
        currentSlideover = E.slideover({
          title: 'Top Slideover',
          content: '<p>This slideover slides down from the top of the screen.</p><p>Perfect for notification panels or headers.</p>',
          position: 'top',
          size: 'sm'
        });
        currentSlideover.open();
      }
    function demoPositionBottom() {
        currentSlideover = E.slideover({
          title: 'Bottom Slideover',
          content: '<p>This slideover slides up from the bottom of the screen.</p><p>Ideal for shopping carts or action sheets.</p>',
          position: 'bottom',
          size: 'md'
        });
        currentSlideover.open();
      }
      // Size demos
    function demoSizeSmall() {
        currentSlideover = E.slideover({
          title: 'Small Slideover (25%)',
          content: '<p>This is a small slideover, taking up 25% of the screen width.</p>',
          size: 'sm'
        });
        currentSlideover.open();
      }
    function demoSizeMedium() {
        currentSlideover = E.slideover({
          title: 'Medium Slideover (50%)',
          content: '<p>This is a medium slideover, taking up 50% of the screen width.</p>',
          size: 'md'
        });
        currentSlideover.open();
      }
    function demoSizeLarge() {
        currentSlideover = E.slideover({
          title: 'Large Slideover (75%)',
          content: '<p>This is a large slideover, taking up 75% of the screen width.</p>',
          size: 'lg'
        });
        currentSlideover.open();
      }
    function demoSizeXL() {
        currentSlideover = E.slideover({
          title: 'Extra Large Slideover (90%)',
          content: '<p>This is an extra large slideover, taking up 90% of the screen width.</p>',
          size: 'xl'
        });
        currentSlideover.open();
      }
    function demoSizeFull() {
        currentSlideover = E.slideover({
          title: 'Full Slideover (100%)',
          content: '<p>This is a full slideover, taking up 100% of the screen width.</p><p>Acts like a full-screen panel.</p>',
          size: 'full'
        });
        currentSlideover.open();
      }
    function demoSizeCustom() {
        currentSlideover = E.slideover({
          title: 'Custom Size (400px)',
          content: '<p>This slideover has a custom width of exactly 400 pixels.</p><p>You can use px, rem, em, or % for custom sizes.</p>',
          size: '400px'
        });
        currentSlideover.open();
      }
      // Advanced features
    function demoNoBackdrop() {
        currentSlideover = E.slideover({
          title: 'No Backdrop',
          content: '<p>This slideover has no backdrop overlay.</p><p>The main content remains fully visible and interactive.</p>',
          backdrop: false
        });
        currentSlideover.open();
      }
    function demoBackdropNoClose() {
        currentSlideover = E.slideover({
          title: 'Backdrop, No Close',
          content: '<p>This slideover has a backdrop but you cannot close it by clicking the backdrop.</p><p>You must use the X button to close.</p>',
          backdrop: true,
          backdropClose: false
        });
        currentSlideover.open();
      }
    function demoNonClosable() {
        currentSlideover = E.slideover({
          title: 'Non-Closable Slideover',
          content: `
                    <p>This slideover has no X button and cannot be closed with the backdrop or Escape key.</p>
                    <p>It must be closed programmatically:</p>
                    <button onclick="currentSlideover.close()" class="btn btn-primary">Close Programmatically</button>
                `,
          closable: false,
          backdropClose: false,
          keyboard: false
        });
        currentSlideover.open();
      }
    function demoCallbacks() {
        const logEl = $(root).find('#callback-log');
        logEl.html('');

        function log(message) {
          const time = D().format('HH:mm:ss');
          logEl.append(`<div>[${time}] ${message}</div>`);
        }

        currentSlideover = E.slideover({
          title: 'Callback Demo',
          content: '<p>Watch the log below for callback messages!</p><p>Try opening and closing this slideover multiple times.</p>',
          onOpen: () => {
            log('🎉 <strong>onOpen</strong> - Slideover opened!');
          },
          onClose: () => {
            log('🔄 <strong>onClose</strong> - Slideover is closing...');
          },
          onClosed: () => {
            log('✅ <strong>onClosed</strong> - Slideover fully closed!');
          }
        });

        log('📝 Slideover created, opening now...');
        currentSlideover.open();
      }
    function demoFormContent() {
        currentSlideover = E.slideover({
          title: 'Contact Form',
          content: `
                    <form id="contact-form" class="p-0">
                        <div class="mb-3">
                            <label class="form-label">Name</label>
                            <input type="text" name="name" class="form-control" required>
                        </div>
                        <div class="mb-3">
                            <label class="form-label">Email</label>
                            <input type="email" name="email" class="form-control" required>
                        </div>
                        <div class="mb-3">
                            <label class="form-label">Subject</label>
                            <input type="text" name="subject" class="form-control">
                        </div>
                        <div class="mb-3">
                            <label class="form-label">Message</label>
                            <textarea name="message" rows="6" class="form-control" required></textarea>
                        </div>
                        <div class="d-flex gap-2">
                            <button type="submit" class="btn btn-primary">
                                <span data-icon="send" data-icon-size="16"></span> Send Message
                            </button>
                            <button type="button" class="btn btn-secondary" onclick="currentSlideover.close()">Cancel</button>
                        </div>
                    </form>
                `,
          size: 'md',
          onOpen: () => {
            $(root).find('#contact-form').on('submit', function (e) {
              e.preventDefault();
              E.toast('Form submitted successfully!', {type: 'success'});
              currentSlideover.close();
            });
          }
        });
        currentSlideover.open();
      }
    function demoProgrammatic() {
        currentSlideover = E.slideover({
          title: 'Programmatic Control',
          content: `
                    <p class="mb-4">Use the buttons below to modify this slideover:</p>
                    <div class="d-flex flex-column gap-2 mb-4">
                        <button onclick="currentSlideover.setTitle('🎯 Title Updated!')" class="btn btn-sm btn-outline">Change Title</button>
                        <button onclick="currentSlideover.setContent('<div class=\\'p-4 bg-success text-white rounded\\'><h4>Content Updated!</h4><p>The content was changed dynamically.</p></div>')" class="btn btn-sm btn-outline">Change Content</button>
                        <hr>
                        <button onclick="currentSlideover.setSize('sm')" class="btn btn-sm btn-secondary">Size: Small</button>
                        <button onclick="currentSlideover.setSize('md')" class="btn btn-sm btn-secondary">Size: Medium</button>
                        <button onclick="currentSlideover.setSize('lg')" class="btn btn-sm btn-secondary">Size: Large</button>
                        <button onclick="currentSlideover.setSize('xl')" class="btn btn-sm btn-secondary">Size: XL</button>
                        <hr>
                        <button onclick="currentSlideover.setPosition('left')" class="btn btn-sm btn-primary">Position: Left</button>
                        <button onclick="currentSlideover.setPosition('right')" class="btn btn-sm btn-primary">Position: Right</button>
                        <button onclick="currentSlideover.setPosition('top')" class="btn btn-sm btn-primary">Position: Top</button>
                        <button onclick="currentSlideover.setPosition('bottom')" class="btn btn-sm btn-primary">Position: Bottom</button>
                    </div>
                    <div class="alert alert-info">
                        <strong>Is Open:</strong> <span id="is-open-status" class="font-mono">?</span>
                    </div>
                `,
          position: 'right',
          size: 'md',
          onOpen: () => {
            // Update status every 500ms
            const interval = setInterval(() => {
              // The slideover sits at the end of the page, not inside the demo.
              const statusEl = $('#is-open-status').get(0);
              if (statusEl && currentSlideover) {
                statusEl.textContent = currentSlideover.isOpen() ? 'true ✅' : 'false ❌';
              } else {
                clearInterval(interval);
              }
            }, 500);
          }
        });
        currentSlideover.open();
      }

    return () => currentSlideover?.close?.();
}
const slideover = Domma.elements.slideover({
    title: 'Callbacks Demo',
    content: '<p>Watch the log for callback messages.</p>',
    onOpen: (instance) => {
        console.log('Slideover opened!', instance);
    },
    onClose: (instance) => {
        console.log('Slideover is closing...', instance);
    },
    onClosed: (instance) => {
        console.log('Slideover fully closed!', instance);
    }
});

Form Integration

Slideovers are excellent for forms - they keep context while allowing focused data entry.

Contact Form

const formSlideover = Domma.elements.slideover({
    title: 'Contact Form',
    content: `
        <form id="contact-form">
            <div class="mb-3">
                <label class="form-label">Name</label>
                <input type="text" name="name" class="form-control" required>
            </div>
            <div class="mb-3">
                <label class="form-label">Email</label>
                <input type="email" name="email" class="form-control" required>
            </div>
            <div class="mb-3">
                <label class="form-label">Message</label>
                <textarea name="message" rows="4" class="form-control"></textarea>
            </div>
            <button type="submit" class="btn btn-primary">Send</button>
            <button type="button" class="btn btn-secondary" onclick="currentSlideover.close()">Cancel</button>
        </form>
    `,
    size: 'md',
    onOpen: () => {
        $('#contact-form').on('submit', function(e) {
            e.preventDefault();
            alert('Form submitted!');
            formSlideover.close();
        });
    }
});

Programmatic Control

Slideovers can be controlled and modified after creation.

Open Control Panel

let slideover = Domma.elements.slideover({
    title: 'Control Panel',
    content: `
        <p>Use the buttons to modify this slideover:</p>
        <button onclick="currentSlideover.setTitle('Updated Title')">Change Title</button>
        <button onclick="currentSlideover.setContent('<p>New content!</p>')">Change Content</button>
        <button onclick="currentSlideover.setSize('sm')">Small</button>
        <button onclick="currentSlideover.setSize('xl')">Extra Large</button>
        <button onclick="currentSlideover.setPosition('left')">Move Left</button>
        <button onclick="currentSlideover.setPosition('right')">Move Right</button>
        <p>Is open: <span id="status">?</span></p>
    `,
    position: 'right'
});

// Check state
console.log(slideover.isOpen());  // false

// Open/close/toggle
slideover.open();
slideover.close();
slideover.toggle();

// Modify content
slideover.setTitle('New Title');
slideover.setContent('<p>Updated!</p>');

// Change size and position
slideover.setSize('md');
slideover.setPosition('left');

// Clean up
slideover.destroy();

API Reference

Factory Method

Domma.elements.slideover(options)

Constructor

Domma.elements.slideover(selector, options)

Options

Option Type Default Description
position String 'right' Position: 'left', 'right', 'top', 'bottom'
size String 'lg' Size: 'sm', 'md', 'lg', 'xl', 'full', or custom (e.g., '400px')
backdrop Boolean true Show semi-transparent backdrop
backdropClose Boolean true Close when clicking backdrop
keyboard Boolean true Enable keyboard shortcuts
closeOnEscape Boolean true Close on Escape key
animation Boolean true Enable slide animation
animationDuration Number 300 Animation duration in milliseconds
title String '' Slideover title (factory method only)
content String|Element '' Slideover content (factory method only)
closable Boolean true Show close button
closeIcon String 'x' Icon name for close button
customSizes Object {} Custom size definitions
onOpen Function null Callback when slideover opens
onClose Function null Callback when slideover starts closing
onClosed Function null Callback when slideover fully closed

Methods

Method Returns Description
open() this Opens the slideover
close() this Closes the slideover
toggle() this Toggles slideover open/closed
isOpen() Boolean Returns true if slideover is open
setTitle(title) this Updates the slideover title
setContent(content) this Updates the slideover content (string or element)
setSize(size) this Changes the slideover size
setPosition(position) this Changes the slideover position
destroy() void Destroys the slideover and cleans up

CSS Customisation

Override these CSS variables to customise Slideover appearance and match your design system.

Variable Default Controls
--dm-surface var(--dm-white) Slideover background
--dm-shadow-xl 0 20px 25px... Slideover shadow
--dm-transition-normal 250ms ease Slide animation speed
--dm-text var(--dm-slate-800) Content text colour

Example Override

:root {
    /* Dark slideover */
    --dm-surface: #1e293b;
    --dm-text: #f1f5f9;
}

Full CSS Customisation Cheat-Sheet →