Skip to content

Foundation Off-Canvas

Off-Canvas is a slide-in navigation pattern, commonly used in mobile interfaces. When triggered, the navigation panel slides in from the edge of the screen. This chapter will introduce various uses of Off-Canvas.

Basic Off-Canvas

html
<div class="off-canvas-wrapper">
    <!-- Off-Canvas Panel -->
    <div class="off-canvas position-left" id="offCanvas" data-off-canvas>
        <ul class="vertical menu">
            <li><a href="#">Home</a></li>
            <li><a href="#">About</a></li>
            <li><a href="#">Services</a></li>
            <li><a href="#">Contact</a></li>
        </ul>
    </div>

    <!-- Main Content Area -->
    <div class="off-canvas-content" data-off-canvas-content>
        <!-- Trigger Button -->
        <button type="button" data-toggle="offCanvas">Open Menu</button>

        <!-- Page Content -->
        <div class="grid-container">
            <h1>Main Page Content</h1>
            <p>Click the button to open the sidebar navigation.</p>
        </div>
    </div>
</div>

Position Options

Off-Canvas can slide in from different directions:

html
<!-- Slide in from left -->
<div class="off-canvas position-left" id="offCanvasLeft" data-off-canvas>
    Content
</div>

<!-- Slide in from right -->
<div class="off-canvas position-right" id="offCanvasRight" data-off-canvas>
    Content
</div>

<!-- Slide in from top -->
<div class="off-canvas position-top" id="offCanvasTop" data-off-canvas>
    Content
</div>

<!-- Slide in from bottom -->
<div class="off-canvas position-bottom" id="offCanvasBottom" data-off-canvas>
    Content
</div>

Overlay

Use data-reveal to control overlay behavior:

html
<!-- Show overlay (default) -->
<div class="off-canvas position-left" id="offCanvas1" data-off-canvas data-reveal="push">
    Content
</div>

<!-- Overlap mode -->
<div class="off-canvas position-left" id="offCanvas2" data-off-canvas data-transition="overlap">
    Content
</div>

Responsive Off-Canvas

Display only on specific screen sizes:

html
<div class="off-canvas-wrapper">
    <!-- Show only on small screens -->
    <div class="off-canvas position-left reveal-for-medium" id="offCanvasResponsive" data-off-canvas>
        <ul class="vertical menu">
            <li><a href="#">Home</a></li>
            <li><a href="#">About</a></li>
        </ul>
    </div>

    <div class="off-canvas-content" data-off-canvas-content>
        <!-- Trigger button shown only on small screens -->
        <button type="button" class="hide-for-medium" data-toggle="offCanvasResponsive">
            Menu
        </button>

        <main>Content</main>
    </div>
</div>

Off-Canvas with Header

html
<div class="off-canvas position-left" id="offCanvasWithHeader" data-off-canvas>
    <div style="background: #1779ba; color: white; padding: 15px;">
        <div class="grid-x align-middle">
            <div class="cell auto">
                <strong>Navigation Menu</strong>
            </div>
            <div class="cell shrink">
                <button class="close-button" aria-label="Close menu" type="button" data-close>
                    <span aria-hidden="true">&times;</span>
                </button>
            </div>
        </div>
    </div>

    <ul class="vertical menu">
        <li><a href="#">Home</a></li>
        <li><a href="#">About</a></li>
        <li><a href="#">Services</a></li>
        <li><a href="#">Contact</a></li>
    </ul>
</div>

Nested Menu

html
<div class="off-canvas position-left" id="offCanvasNested" data-off-canvas>
    <ul class="vertical menu" data-drilldown>
        <li>
            <a href="#">Products</a>
            <ul class="menu vertical nested">
                <li><a href="#">Product A</a></li>
                <li><a href="#">Product B</a></li>
                <li>
                    <a href="#">Product C</a>
                    <ul class="menu vertical nested">
                        <li><a href="#">C-1</a></li>
                        <li><a href="#">C-2</a></li>
                    </ul>
                </li>
            </ul>
        </li>
        <li><a href="#">Services</a></li>
        <li><a href="#">About</a></li>
    </ul>
</div>

Dual Off-Canvas

html
<div class="off-canvas-wrapper">
    <!-- Left Panel -->
    <div class="off-canvas position-left" id="leftPanel" data-off-canvas>
        <h4>Navigation Menu</h4>
        <ul class="vertical menu">
            <li><a href="#">Home</a></li>
            <li><a href="#">About</a></li>
        </ul>
    </div>

    <!-- Right Panel -->
    <div class="off-canvas position-right" id="rightPanel" data-off-canvas>
        <h4>Shopping Cart</h4>
        <ul class="no-bullet">
            <li>Product 1 - $99</li>
            <li>Product 2 - $199</li>
        </ul>
        <hr>
        <p><strong>Total: $298</strong></p>
        <a class="button expanded" href="#">Checkout</a>
    </div>

    <!-- Main Content -->
    <div class="off-canvas-content" data-off-canvas-content>
        <div class="top-bar">
            <div class="top-bar-left">
                <button type="button" data-toggle="leftPanel">Menu</button>
            </div>
            <div class="top-bar-right">
                <button type="button" data-toggle="rightPanel">Cart</button>
            </div>
        </div>
        <main>Content</main>
    </div>
</div>

Configuration Options

html
<div class="off-canvas position-left" id="configOffCanvas" data-off-canvas
     data-transition="overlap"
     data-close-on-click="true"
     data-content-overlay="true"
     data-force-top="true">
    Content
</div>
OptionDescriptionDefault
data-transitionTransition effect (push/overlap)push
data-close-on-clickClose on overlay clicktrue
data-content-overlayShow content overlaytrue
data-force-topForce scroll to toptrue

JavaScript API

javascript
// Open
$('#offCanvas').foundation('open');

// Close
$('#offCanvas').foundation('close');

// Toggle
$('#offCanvas').foundation('toggle');

// Events
$('#offCanvas').on('opened.zf.offCanvas', function() {
    console.log('Off-Canvas opened');
});

$('#offCanvas').on('closed.zf.offCanvas', function() {
    console.log('Off-Canvas closed');
});

Complete Example

html
<!DOCTYPE html>
<html class="no-js" lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Foundation Off-Canvas Example</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/foundation-sites@6.7.5/dist/css/foundation.min.css">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/foundicons/3.0.0/foundation-icons.min.css">
    <style>
        .off-canvas {
            background: #2c3e50;
        }
        .off-canvas .menu a {
            color: #ecf0f1;
            padding: 15px 20px;
        }
        .off-canvas .menu a:hover {
            background: rgba(255,255,255,0.1);
        }
        .off-canvas .menu a i {
            margin-right: 10px;
        }
        .off-canvas-header {
            background: #1779ba;
            color: white;
            padding: 15px 20px;
        }
        .off-canvas-header h4 {
            margin: 0;
            color: white;
        }
        .user-profile {
            padding: 20px;
            text-align: center;
            border-bottom: 1px solid rgba(255,255,255,0.1);
        }
        .user-profile img {
            width: 80px;
            height: 80px;
            border-radius: 50%;
            margin-bottom: 10px;
        }
        .user-profile h5 {
            color: white;
            margin: 0;
        }
        .user-profile p {
            color: #bdc3c7;
            margin: 0;
            font-size: 14px;
        }
        .main-content {
            min-height: 100vh;
            padding: 20px;
        }
    </style>
</head>
<body>
    <div class="off-canvas-wrapper">
        <!-- Left Off-Canvas -->
        <div class="off-canvas position-left" id="leftOffCanvas" data-off-canvas>
            <div class="off-canvas-header">
                <div class="grid-x align-middle">
                    <div class="cell auto">
                        <h4>Navigation Menu</h4>
                    </div>
                    <div class="cell shrink">
                        <button class="close-button" aria-label="Close" type="button" data-close style="color: white;">
                            <span aria-hidden="true">&times;</span>
                        </button>
                    </div>
                </div>
            </div>

            <div class="user-profile">
                <img src="https://via.placeholder.com/80" alt="User Avatar">
                <h5>John Doe</h5>
                <p>Frontend Developer</p>
            </div>

            <ul class="vertical menu">
                <li><a href="#"><i class="fi-home"></i> Home</a></li>
                <li><a href="#"><i class="fi-torso"></i> Profile</a></li>
                <li><a href="#"><i class="fi-mail"></i> Messages</a></li>
                <li><a href="#"><i class="fi-widget"></i> Settings</a></li>
                <li><a href="#"><i class="fi-info"></i> Help</a></li>
                <li><a href="#"><i class="fi-power"></i> Logout</a></li>
            </ul>
        </div>

        <!-- Right Off-Canvas (Shopping Cart) -->
        <div class="off-canvas position-right" id="rightOffCanvas" data-off-canvas style="background: white; width: 300px;">
            <div style="background: #3adb76; color: white; padding: 15px 20px;">
                <div class="grid-x align-middle">
                    <div class="cell auto">
                        <h4 style="margin: 0; color: white;">Shopping Cart</h4>
                    </div>
                    <div class="cell shrink">
                        <button class="close-button" aria-label="Close" type="button" data-close>
                            <span aria-hidden="true">&times;</span>
                        </button>
                    </div>
                </div>
            </div>

            <div style="padding: 20px;">
                <div class="grid-x" style="margin-bottom: 15px; padding-bottom: 15px; border-bottom: 1px solid #eee;">
                    <div class="cell shrink">
                        <img src="https://via.placeholder.com/60" alt="Product Image" style="border-radius: 4px;">
                    </div>
                    <div class="cell auto" style="padding-left: 10px;">
                        <strong>Product Name 1</strong>
                        <p style="margin: 0; color: #666; font-size: 14px;">Qty: 1</p>
                        <p style="margin: 0; color: #cc4b37; font-weight: bold;">$99.00</p>
                    </div>
                </div>

                <div class="grid-x" style="margin-bottom: 15px; padding-bottom: 15px; border-bottom: 1px solid #eee;">
                    <div class="cell shrink">
                        <img src="https://via.placeholder.com/60" alt="Product Image" style="border-radius: 4px;">
                    </div>
                    <div class="cell auto" style="padding-left: 10px;">
                        <strong>Product Name 2</strong>
                        <p style="margin: 0; color: #666; font-size: 14px;">Qty: 2</p>
                        <p style="margin: 0; color: #cc4b37; font-weight: bold;">$199.00</p>
                    </div>
                </div>

                <div style="background: #f4f4f4; padding: 15px; border-radius: 4px; margin-bottom: 15px;">
                    <div class="grid-x">
                        <div class="cell auto">Subtotal</div>
                        <div class="cell shrink"><strong>$298.00</strong></div>
                    </div>
                </div>

                <a class="button expanded success" href="#">Checkout</a>
                <a class="button hollow expanded" href="#">Continue Shopping</a>
            </div>
        </div>

        <!-- Main Content Area -->
        <div class="off-canvas-content" data-off-canvas-content>
            <!-- Top Navigation -->
            <div class="top-bar" style="background: #2c3e50;">
                <div class="top-bar-left">
                    <ul class="menu">
                        <li>
                            <button class="button clear" type="button" data-toggle="leftOffCanvas" style="color: white;">
                                <i class="fi-list"></i>
                            </button>
                        </li>
                        <li class="menu-text" style="color: white;">Website Name</li>
                    </ul>
                </div>
                <div class="top-bar-right">
                    <ul class="menu">
                        <li>
                            <button class="button clear" type="button" data-toggle="rightOffCanvas" style="color: white; position: relative;">
                                <i class="fi-shopping-cart"></i>
                                <span class="badge alert" style="position: absolute; top: 0; right: 0; font-size: 10px;">2</span>
                            </button>
                        </li>
                    </ul>
                </div>
            </div>

            <!-- Main Content -->
            <div class="main-content">
                <div class="grid-container">
                    <h1>Off-Canvas Navigation Example</h1>
                    <p>Click the menu icon in the top left to open the navigation menu, click the cart icon in the top right to view the shopping cart.</p>

                    <div class="callout">
                        <h4>Off-Canvas Features</h4>
                        <ul>
                            <li>Slide in from screen edge</li>
                            <li>Support multiple directions (left, right, top, bottom)</li>
                            <li>Perfect for mobile navigation</li>
                            <li>Can contain any content</li>
                        </ul>
                    </div>

                    <div class="grid-x grid-margin-x small-up-1 medium-up-3">
                        <div class="cell">
                            <div class="card">
                                <img src="https://via.placeholder.com/300x200" alt="Product">
                                <div class="card-section">
                                    <h4>Product 1</h4>
                                    <p>Product description...</p>
                                    <a class="button" href="#">View Details</a>
                                </div>
                            </div>
                        </div>
                        <div class="cell">
                            <div class="card">
                                <img src="https://via.placeholder.com/300x200" alt="Product">
                                <div class="card-section">
                                    <h4>Product 2</h4>
                                    <p>Product description...</p>
                                    <a class="button" href="#">View Details</a>
                                </div>
                            </div>
                        </div>
                        <div class="cell">
                            <div class="card">
                                <img src="https://via.placeholder.com/300x200" alt="Product">
                                <div class="card-section">
                                    <h4>Product 3</h4>
                                    <p>Product description...</p>
                                    <a class="button" href="#">View Details</a>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/foundation-sites@6.7.5/dist/js/foundation.min.js"></script>
    <script>$(document).foundation();</script>
</body>
</html>

Off-Canvas Best Practices

  1. Mobile-First: Off-Canvas is best suited for mobile navigation
  2. Clear Triggers: Use recognizable icons or buttons
  3. Close Button: Provide obvious ways to close
  4. Appropriate Width: Don't take up too much screen space
  5. Content Organization: Organize panel content reasonably

Summary

In this chapter, we learned:

  • Creating basic Off-Canvas
  • Different positions (left, right, top, bottom)
  • Responsive Off-Canvas
  • Off-Canvas with headers and nested menus
  • Dual Off-Canvas
  • JavaScript API

Next chapter, we will learn Foundation Magellan.

Content is for learning and research only.