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.
<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.
<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.
<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
<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;
}