IndiaCN UI

Offcanvas

A sliding panel that appears from any edge of the screen.

Introduction

Offcanvas components slide in from the edges of the viewport, useful for navigation menus, filters, or supplementary content. Built on Radix UI Dialog for accessibility.

Installation

import {
Offcanvas, OffcanvasTrigger, OffcanvasContent,
OffcanvasHeader, OffcanvasTitle, OffcanvasBody,
} from '@/components/ui/offcanvas';

Usage

<Offcanvas>
<OffcanvasTrigger asChild>
  <Button>Open</Button>
</OffcanvasTrigger>
<OffcanvasContent>
  <OffcanvasHeader><OffcanvasTitle>Title</OffcanvasTitle></OffcanvasHeader>
  <OffcanvasBody>Content here</OffcanvasBody>
</OffcanvasContent>
</Offcanvas>

Examples

Default

OffcanvasDefault
import { Button } from '@/components/ui/button';
import { Offcanvas, OffcanvasTrigger, OffcanvasContent, OffcanvasHeader, OffcanvasTitle, OffcanvasBody } from '@/components/ui/offcanvas';

export default function Component() {
  return (
    <Offcanvas>
      <OffcanvasTrigger asChild><Button variant="outlined">Open Offcanvas</Button></OffcanvasTrigger>
      <OffcanvasContent>
        <OffcanvasHeader><OffcanvasTitle>Offcanvas</OffcanvasTitle></OffcanvasHeader>
        <OffcanvasBody><p className="text-sm">Offcanvas content here.</p></OffcanvasBody>
      </OffcanvasContent>
    </Offcanvas>
  );
}

Sides

Use the side prop to control which edge the panel slides from.

OffcanvasSides
import { Button } from '@/components/ui/button';
import { Offcanvas, OffcanvasTrigger, OffcanvasContent, OffcanvasHeader, OffcanvasTitle, OffcanvasBody } from '@/components/ui/offcanvas';

export default function Component() {
  return (
    <div className="flex gap-2">
      {(['left', 'right', 'top', 'bottom'] as const).map((side) => (
        <Offcanvas key={side}>
          <OffcanvasTrigger asChild><Button variant="outlined" size="sm">{side}</Button></OffcanvasTrigger>
          <OffcanvasContent side={side}>
            <OffcanvasHeader><OffcanvasTitle>Offcanvas {side}</OffcanvasTitle></OffcanvasHeader>
            <OffcanvasBody><p className="text-sm">Slides from {side}.</p></OffcanvasBody>
          </OffcanvasContent>
        </Offcanvas>
      ))}
    </div>
  );
}

Body Scroll

Use the bodyScroll prop to allow the page body to remain scrollable while the offcanvas is open.

OffcanvasBodyScroll
'use client';
/* eslint-disable eslint-frontend-rules/enforce-typography-components */

import { Button } from '@/components/ui/button';
import {
  Offcanvas,
  OffcanvasBody,
  OffcanvasContent,
  OffcanvasHeader,
  OffcanvasTitle,
  OffcanvasTrigger,
} from '@/components/ui/offcanvas';

export function OffcanvasDefault() {
  return (
    <Offcanvas>
      <OffcanvasTrigger asChild>
        <Button variant='outlined'>Open Offcanvas</Button>
      </OffcanvasTrigger>
      <OffcanvasContent>
        <OffcanvasHeader>
          <OffcanvasTitle>Offcanvas</OffcanvasTitle>
        </OffcanvasHeader>
        <OffcanvasBody>
          <p className='text-sm'>
            Some text as placeholder. In real life you can have the elements you have chosen.
          </p>
        </OffcanvasBody>
      </OffcanvasContent>
    </Offcanvas>
  );
}

export function OffcanvasSides() {
  return (
    <div className='flex flex-wrap gap-2'>
      {(['left', 'right', 'top', 'bottom'] as const).map(side => (
        <Offcanvas key={side}>
          <OffcanvasTrigger asChild>
            <Button variant='outlined' size='sm'>
              {side}
            </Button>
          </OffcanvasTrigger>
          <OffcanvasContent side={side}>
            <OffcanvasHeader>
              <OffcanvasTitle>Offcanvas {side}</OffcanvasTitle>
            </OffcanvasHeader>
            <OffcanvasBody>
              <p className='text-sm'>Content slides in from the {side}.</p>
            </OffcanvasBody>
          </OffcanvasContent>
        </Offcanvas>
      ))}
    </div>
  );
}

export function OffcanvasBodyScroll() {
  return (
    <Offcanvas>
      <OffcanvasTrigger asChild>
        <Button variant='outlined'>Enable Body Scroll</Button>
      </OffcanvasTrigger>
      <OffcanvasContent bodyScroll>
        <OffcanvasHeader>
          <OffcanvasTitle>Body Scrolling</OffcanvasTitle>
        </OffcanvasHeader>
        <OffcanvasBody>
          <p className='text-sm'>
            Try scrolling the rest of the page while this offcanvas is open. The backdrop is hidden
            and body scroll is enabled.
          </p>
        </OffcanvasBody>
      </OffcanvasContent>
    </Offcanvas>
  );
}

Note: The offcanvas panel width is 400px for left/right sides, and height is 30vh for top/bottom sides.

API Reference

OffcanvasContent

PropTypeDefaultDescription
sideleft | right | top | bottomrightSlide direction
bodyScrollbooleanfalseAllow body scrolling while open

On this page