DevExtreme Vue - Getting Started with Navigation Drawer

NOTE
Before starting the tutorial, make sure that you have installed DevExtreme in your application as described in the Installation section (for JavaScript libraries), the Getting Started article (for ASP.NET MVC 5 Controls), or the Configure a Visual Studio Project article (for ASP.NET Core Controls).

The Drawer is a dismissible or permanently visible panel used for navigation in responsive web application layouts.

DevExtreme supplies application templates for Angular, Vue, and React. They implement a responsive layout that uses the Drawer. You can use these templates instead of following the tutorial. Refer to the documentation on GitHub for more information:

If the templates are unsuitable or you use jQuery, follow the instructions in this tutorial. We create a Drawer that allows a user to switch between pages. The Drawer is opened and closed via a button on a toolbar.

Refer to the subtopics for details on every configuration step. You can also see the full code below:

jQuery
index.js
index.html
index.css
inbox.html
sent-mail.html
trash.html
spam.html
$(function() {
    $("#view").load( "./inbox.html" );

    $("#toolbar").dxToolbar({
        items: [{
            widget: "dxButton",
            location: "before",
            options: {
                icon: "menu",
                onClick: function() {
                    drawer.toggle();
                }
            }
        }]
    });

    const drawer = $("#drawer").dxDrawer({
        minSize: 37,
        height: 250,
        revealMode: "expand",
        openedStateMode: "overlap",
        template: function() {
            const $list = $("<div/>").dxList({
                items: [
                    { id: 1, text: "Inbox", icon: "message", filePath: "inbox" },
                    { id: 2, text: "Sent Mail", icon: "check", filePath: "sent-mail" },
                    { id: 3, text: "Trash", icon: "trash", filePath: "trash" },
                    { id: 4, text: "Spam", icon: "mention", filePath: "spam" }
                ],
                width: 200,
                height: 200,
                selectionMode: "single",
                onSelectionChanged: function(e) {
                    $("#view").load( e.addedItems[0].filePath + ".html" );
                    drawer.hide();
                }
            });
            return $list;
        }
    }).dxDrawer("instance");
})
<html>
    <head>
        <!-- ... -->
        <script type="text/javascript" src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
        <link rel="stylesheet" href="https://cdn3.devexpress.com/jslib/19.2.15/css/dx.common.css">
        <link rel="stylesheet" href="https://cdn3.devexpress.com/jslib/19.2.15/css/dx.light.css">
        <link rel="stylesheet" href="index.css">
        <script type="text/javascript" src="https://cdn3.devexpress.com/jslib/19.2.15/js/dx.all.js"></script>
        <script type="text/javascript" src="index.js"></script>
    </head>
    <body>
        <div id="toolbar"></div>
        <div id="drawer">
            <div id="view"></div>
        </div>
    </body>
</html>
.dx-overlay-content {
    background-color: lightgray;
}
#toolbar {
    background-color: rgba(191, 191, 191, .15);
    padding: 5px 10px;
}
.dx-toolbar-button .dx-button {
    background-color: rgba(191, 191, 191, -0.15);
    border: none;
}
.dx-toolbar-button > .dx-toolbar-item-content {
    margin-left: -7px;
}
.dx-list-item-icon {
    margin-right: 10px;
}
#view {
    margin-left: 10px;
    margin-top: 10px;
}
<div>Inbox</div>
<div>Sent Mail</div>
<div>Trash</div>
<div>Spam</div>
Angular
app.component.html
app.component.ts
app.component.css
app.module.ts
app-routing.module.ts
inbox.component.ts
sent-mail.component.ts
spam.component.ts
trash.component.ts
<dx-toolbar id="toolbar">
    <dxi-item 
        widget="dxButton"
        [options]="buttonOptions"
        location="before">
    </dxi-item>
</dx-toolbar>
<dx-drawer
    template="template"
    [height]="250"
    [(opened)]="isDrawerOpen"
    [minSize]="37"
    revealMode="expand"
    openedStateMode="overlap">
    <div *dxTemplate="let data of 'template'">
        <dx-list
            [items]="navigation"
            [width]="200"
            selectionMode="single"
            (onSelectionChanged)="loadView($event)">
        </dx-list>
    </div>
    <div id="view"><router-outlet></router-outlet></div>
</dx-drawer>
import { Component } from "@angular/core";
import { Router } from "@angular/router";

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css'],
    providers: []
})

export class AppComponent {
    navigation: any;
    isDrawerOpen: Boolean = false;
    buttonOptions: any;

    constructor(private router: Router) {
        this.buttonOptions = {
            icon: "menu",
            onClick: () => {
                this.isDrawerOpen = !this.isDrawerOpen;
            }
        };
        this.navigation = [
            { id: 1, text: "Inbox", icon: "message", filePath: "inbox" },
            { id: 2, text: "Sent Mail", icon: "check", filePath: "sent-mail" },
            { id: 3, text: "Trash", icon: "trash", filePath: "trash" },
            { id: 4, text: "Spam", icon: "mention", filePath: "spam" }
        ];
    }

    loadView(e) {
        this.router.navigate([e.addedItems[0].filePath]);
        this.isDrawerOpen = false;
    }
}
::ng-deep .dx-overlay-content {
    background-color: lightgray;
}
::ng-deep #toolbar {
    background-color: rgba(191, 191, 191, .15);
    padding: 5px 10px;
}
::ng-deep .dx-toolbar-button .dx-button {
    background-color: rgba(191, 191, 191, -0.15);
    border: none;
}
::ng-deep .dx-toolbar-button > .dx-toolbar-item-content {
    margin-left: -7px;
}
::ng-deep .dx-list-item-icon {
    margin-right: 10px;
}
::ng-deep #view {
    margin-left: 10px;
    margin-top: 10px;
}
import { BrowserModule } from "@angular/platform-browser";
import { NgModule } from "@angular/core";
import { AppComponent } from "./app.component";

import { AppRoutingModule } from "./app-routing.module";
import { DxDrawerModule, DxToolbarModule, DxListModule } from "devextreme-angular";

@NgModule({
    declarations: [
        AppComponent
    ],
    imports: [
        BrowserModule,
        AppRoutingModule,
        DxDrawerModule,
        DxToolbarModule,
        DxListModule
    ],
    providers: [],
    bootstrap: [AppComponent]
})
export class AppModule { }
import { NgModule } from "@angular/core";
import { Routes, RouterModule } from "@angular/router";
import { InboxComponent } from "./views/inbox.component";
import { SentMailComponent } from "./views/sent-mail.component";
import { TrashComponent } from "./views/trash.component";
import { SpamComponent } from "./views/spam.component";

const routes: Routes = [
    { path: '', redirectTo: '/inbox', pathMatch: 'full' },
    { path: 'inbox', component: InboxComponent },
    { path: 'sent-mail', component: SentMailComponent },
    { path: 'trash', component: TrashComponent },
    { path: 'spam', component: SpamComponent },
];

@NgModule({
    imports: [RouterModule.forRoot(routes)],
    exports: [RouterModule],
    declarations: [
        InboxComponent,
        SentMailComponent,
        TrashComponent,
        SpamComponent
    ]
})
export class AppRoutingModule { }
import { Component } from "@angular/core";

@Component({
    selector: 'app-inbox',
    template: '<div>Inbox</div>'
})
export class InboxComponent { constructor() { } }
import { Component } from "@angular/core";

@Component({
    selector: 'app-sent-mail',
    template: '<div>Sent Mail</div>'
})
export class SentMailComponent { constructor() { } }
import { Component } from "@angular/core";

@Component({
    selector: 'app-spam',
    template: '<div>Spam</div>'
})
export class SpamComponent { constructor() { } }
import { Component } from "@angular/core";

@Component({
    selector: 'app-trash',
    template: '<div>Trash</div>'
})
export class TrashComponent { constructor() { } }
Vue
App.vue
NavigationList.vue
main.js
Inbox.vue
SentMail.vue
Spam.vue
Trash.vue
<template>
    <div>
        <DxToolbar id="toolbar">
            <DxItem
                widget="dxButton"
                :options="buttonOptions"
                location="before"
            />
        </DxToolbar>
        <DxDrawer
            opened-state-mode="overlap"
            reveal-mode="expand"
            :opened.sync="isDrawerOpen"
            :minSize="37"
            :height="250"
            template="list">
            <template #list>
                <NavigationList
                    @navigated="isDrawerOpen = false"
                />
            </template>
            <div id="view">
                <router-view></router-view>
            </div>
        </DxDrawer>
    </div>
</template>

<script>
import DxDrawer from 'devextreme-vue/drawer';
import DxToolbar, { DxItem } from 'devextreme-vue/toolbar';
import NavigationList from './components/NavigationList.vue';

export default {
    components: {
        DxDrawer,
        DxToolbar,
        DxItem,
        NavigationList
    },
    data() {
        return {
            buttonOptions: {
                icon: "menu",
                onClick: () => {
                    this.isDrawerOpen = !this.isDrawerOpen;
                }
            },
            isDrawerOpen: false
        };
    }
};
</script>

<style>
.dx-overlay-content {
    background-color: lightgray;
}
#view {
    margin-left: 10px;
    margin-top: 10px;
}
#toolbar {
    background-color: rgba(191, 191, 191, 0.15);
    padding: 5px 10px;
}
.dx-toolbar-button .dx-button {
    background-color: rgba(191, 191, 191, -0.15);
    border: none;
}
.dx-toolbar-button > .dx-toolbar-item-content {
    margin-left: -7px;
}
.dx-list-item-icon {
    margin-right: 10px;
}
</style>
<template>
    <DxList
        :width="200"
        selection-mode="single"
        :items="navigation"
        @selection-changed="loadView($event)"
    />
</template>
<script>
import { DxList } from "devextreme-vue/list";

export default {
    components: {
        DxList
    },
    data() {
        const navigation = [
            { id: 1, text: "Inbox", icon: "message", filePath: "inbox" },
            { id: 2, text: "Sent Mail", icon: "check", filePath: "sent-mail" },
            { id: 3, text: "Trash", icon: "trash", filePath: "trash" },
            { id: 4, text: "Spam", icon: "mention", filePath: "spam" }
        ];
        return {
            navigation
        };
    },
    methods: {
        loadView(e) {
            this.$router.push(e.addedItems[0].filePath);
            this.$emit('navigated');
        }
    }
}
</script>
import Vue from 'vue';
import VueRouter from 'vue-router';

import 'devextreme/dist/css/dx.common.css';
import 'devextreme/dist/css/dx.light.css';

import App from './App.vue';
import InboxComponent from "./components/Inbox.vue";
import SentMailComponent from "./components/SentMail.vue";
import TrashComponent from "./components/Trash.vue";
import SpamComponent from "./components/Spam.vue";

Vue.config.productionTip = false;

Vue.use(VueRouter);

const routes = [
    { path: "", redirect: "/inbox" },
    { path: "/inbox", component: InboxComponent },
    { path: "/sent-mail", component: SentMailComponent },
    { path: "/trash", component: TrashComponent },
    { path: "/spam", component: SpamComponent }
];

const router = new VueRouter({
    mode: "history",
    routes
});

new Vue({
    render: h => h(App),
    router
}).$mount('#app')
<template>
    <div>Inbox</div>
</template>

<script>
export default {}
</script>
<template>
    <div>Sent mail</div>
</template>

<script>
export default {}
</script>
<template>
    <div>Spam</div>
</template>

<script>
export default {}
</script>
<template>
    <div>Trash</div>
</template>

<script>
export default {}
</script>
React
DxComponent.js
NavigationList.js
App.js
history.js
DxComponent.css
Inbox.js
SentMail.js
Spam.js
Trash.js
import React from "react";

import "devextreme/dist/css/dx.common.css";
import "devextreme/dist/css/dx.light.css";
import "./DxComponent.css";

import { Drawer } from "devextreme-react/drawer";
import { Toolbar, Item } from "devextreme-react/toolbar";
import NavigationList from "./NavigationList";

import { Router, Route } from "react-router-dom";

import Inbox from "./views/Inbox";
import Trash from "./views/Trash";
import SentMail from "./views/SentMail";
import Spam from "./views/Spam";

import history from "./history";

class DxComponent extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            isDrawerOpen: false
        };
        this.buttonOptions = {
            icon: "menu",
            onClick: () => {
                this.setState({ isDrawerOpen: !this.state.isDrawerOpen });
            }
        };
    }

    renderList = () => {
        const stateHandler = (newState) => this.setState(newState);
        return (
            <NavigationList stateHandler={stateHandler} />
        );
    }

    render() {
        return (
            <React.Fragment>
                <Toolbar id="toolbar">
                    <Item 
                        widget="dxButton" 
                        options={this.buttonOptions} 
                        location="before" />
                </Toolbar>
                <Drawer
                    minSize={37}
                    height={250}
                    revealMode="expand"
                    openedStateMode="overlap"
                    render={this.renderList}
                    opened={this.state.isDrawerOpen} >
                    <div id="view">
                        <Router history={history}>
                            <div>
                                <Route exact path="/" component={Inbox} />
                                <Route exact path="/inbox" component={Inbox} />
                                <Route exact path="/sent-mail" component={SentMail} />
                                <Route exact path="/spam" component={Spam} />
                                <Route exact path="/trash" component={Trash} />
                            </div>
                        </Router>
                    </div>
                </Drawer>
            </React.Fragment>
        );
    }
}
export default DxComponent;
import React from "react";
import List from "devextreme-react/list";
import history from "./history";

const navigation = [
    { id: 1, text: "Inbox", icon: "message", filePath: "inbox" },
    { id: 2, text: "Sent Mail", icon: "check", filePath: "sent-mail" },
    { id: 3, text: "Trash", icon: "trash", filePath: "trash" },
    { id: 4, text: "Spam", icon: "mention", filePath: "spam" }
];

class NavigationList extends React.PureComponent {
    loadView = (e) => {
        history.push(e.addedItems[0].filePath);
        this.props.stateHandler({ isDrawerOpen: false });
    }
    render() {
        return (
            <React.Fragment>
                <List
                    items={navigation}
                    width={200} 
                    selectionMode="single"
                    onSelectionChanged={this.loadView} />
            </React.Fragment>
        );
    }
}
export default NavigationList;
import React, { Component } from "react";
import DxComponent from "./components/DxComponent";

class App extends Component {
    render() {
        return (
            <div className="App">
                <DxComponent />
            </div>
        );
    }
}
export default App;
import { createBrowserHistory } from "history"

export default createBrowserHistory()
.dx-overlay-content {
    background-color: lightgray;
}
#toolbar {
    background-color: rgba(191, 191, 191, .15);
    padding: 5px 10px;
}
.dx-toolbar-button .dx-button {
    background-color: rgba(191, 191, 191, -0.15);
    border: none;
}
.dx-toolbar-button > .dx-toolbar-item-content {
    margin-left: -7px;
}
.dx-list-item-icon {
    margin-right: 10px;
}
#view {
    margin-left: 10px;
    margin-top: 10px;
}
import React from "react";

class Inbox extends React.Component {
    render() {
        return (
            <div>Inbox</div>
        );
    }
}
export default Inbox;
import React from "react";

class SentMail extends React.Component {
    render() {
        return (
            <div>Sent Mail</div>
        );
    }
}
export default SentMail;
import React from "react";

class Spam extends React.Component {
    render() {
        return (
            <div>Spam</div>
        );
    }
}
export default Spam;
import React from "react";

class Trash extends React.Component {
    render() {
        return (
            <div>Trash</div>
        );
    }
}
export default Trash;
ASP.NET MVC Controls
_Layout.cshtml
HomeController.cs
Site.css
Index.cshtml
Deleted.cshtml
Sent.cshtml
Spam.cshtml
@(Html.DevExtreme().Toolbar()
    .ID("layout-toolbar")
    .Items(items => {
        items.Add().Widget(w => w.Button()
            .Icon("menu")
            .OnClick("button_clickHandler")
        ).Location(ToolbarItemLocation.Before);
    })
)

@(Html.DevExtreme().Drawer()
    .ID("layout-drawer")
    .MinSize(37)
    .Height(250)
    .Opened(new JS("JSON.parse(sessionStorage.getItem('isDrawerOpen'))"))
    .RevealMode(DrawerRevealMode.Expand)
    .OpenedStateMode(DrawerOpenedStateMode.Overlap)        
    .Template(@<text>
        @(Html.DevExtreme().List()
            .Width(200)
            .OnInitialized("list_onInitialized")
            .Items(items => {
                items.Add().Text("Inbox").Icon("message").Option("path", @Url.Action("Index"));
                items.Add().Text("Sent Mail").Icon("check").Option("path", @Url.Action("Sent"));
                items.Add().Text("Deleted").Icon("trash").Option("path", @Url.Action("Deleted"));
                items.Add().Text("Spam").Icon("mention").Option("path", @Url.Action("Spam"));
            })
            .KeyExpr("path")
            .SelectionMode(ListSelectionMode.Single)
            .OnSelectionChanged("list_onSelectionChanged")
        )
    </text>)
    .Content(@<text>@RenderBody()</text>)
)

<script type="text/javascript">
    function button_clickHandler() {
        const drawer = $("#layout-drawer").dxDrawer("instance");
        drawer.toggle();
        sessionStorage.setItem("isDrawerOpen", JSON.stringify(drawer.option("opened")));
    }

    function list_onSelectionChanged(e) {
        document.location.pathname = e.addedItems[0].path;
        $("#layout-drawer").dxDrawer("hide");
    }

    function list_onInitialized(e) {
        const t = "@Url.Action()";
        e.component.option("selectedItemKeys", [ "@Url.Action()" ])
    }
</script>
using System.Web.Mvc;

namespace DevExtremeApp.Controllers {
    public class HomeController : Controller {
        public ActionResult Index() {
            return View();
        }

        public ActionResult Deleted() {
            return View();
        }

        public ActionResult Sent() {
            return View();
        }

        public ActionResult Spam() {
            return View();
        }
    }
}
.dx-overlay-content {
    background-color: lightgray;
}

.drawer-view-content {
    margin-left: 10px;
    margin-top: 10px;
}

#layout-toolbar {
    background-color: rgba(191, 191, 191, .15);
    padding: 5px 10px;
}

#layout-toolbar .dx-toolbar-button .dx-button {
    background-color: rgba(191, 191, 191, -0.15);
    border: none;
}

#layout-toolbar .dx-toolbar-button > .dx-toolbar-item-content {
    margin-left: -7px;
}

#layout-toolbar .dx-list-item-icon {
    margin-right: 10px;
}
<div class="drawer-view-content">Inbox</div>
<div class="drawer-view-content">Deleted</div>
<div class="drawer-view-content">Sent</div>
<div class="drawer-view-content">Spam</div>

Create the Drawer

Wrap the view in the Drawer and specify a template for the Drawer's content. Inside the template, set the Drawer's width. You can use the nested widget's width option for this (see Implement Navigation), but in this tutorial, we use the width CSS property. The Drawer's height adjusts to the view's height (specified via the height option).

In addition, you can specify the minSize option to make the Drawer partially visible in the closed state.

jQuery
index.html
index.js
index.css
<html>
    <head>
        <!-- ... -->
        <script type="text/javascript" src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
        <link rel="stylesheet" href="https://cdn3.devexpress.com/jslib/19.2.15/css/dx.common.css">
        <link rel="stylesheet" href="https://cdn3.devexpress.com/jslib/19.2.15/css/dx.light.css">
        <link rel="stylesheet" href="index.css">
        <script type="text/javascript" src="https://cdn3.devexpress.com/jslib/19.2.15/js/dx.all.js"></script>
        <script type="text/javascript" src="index.js"></script>
    </head>
    <body>
        <div id="drawer">
            <div id="view">View content</div>
        </div>
    </body>
</html>
$(function() {
    $("#drawer").dxDrawer({
        template: function(e) {
            return $("<div style='width: 150px'>Drawer content</div>");
        },
        height: 250,
        minSize: 37
    });
});
.dx-overlay-content {
    background-color: lightgray;
}
#view {
    margin-left: 10px;
    margin-top: 10px;
}
Angular
app.component.html
app.component.ts
app.module.ts
app.component.css
<dx-drawer
    template="template"
    [height]="250"
    [minSize]="37">
    <div *dxTemplate="let data of 'template'">
        <div style="width: 150px">Drawer content</div>
    </div>
    <div>View content</div>
</dx-drawer>
import { Component } from "@angular/core";

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
})

export class AppComponent {

}
import { BrowserModule } from "@angular/platform-browser";
import { NgModule } from "@angular/core";
import { AppComponent } from "./app.component";

import { DxDrawerModule } from "devextreme-angular";

@NgModule({
    declarations: [
        AppComponent
    ],
    imports: [
        BrowserModule,
        DxDrawerModule
    ],
    providers: [],
    bootstrap: [AppComponent]
})
export class AppModule { }
::ng-deep .dx-overlay-content {
    background-color: lightgray;
}
::ng-deep #view {
    margin-left: 10px;
    margin-top: 10px;
}
Vue
App.vue
<template>
    <div>
        <DxDrawer
            :minSize="37"
            :height="250"
            template="list">
            <template #list>
                <div style="width: 150px">Drawer content</div>
            </template>
            <div id="view">
                <div>View content</div>
            </div>
        </DxDrawer>
    </div>
</template>

<script>
import DxDrawer from 'devextreme-vue/drawer';

export default {
    components: {
        DxDrawer
    }
};
</script>

<style>
.dx-overlay-content {
    background-color: lightgray;
}
#view {
    margin-left: 10px;
    margin-top: 10px;
}
</style>
React
DxComponent.js
DxComponent.css
App.js
import React from "react";

import "devextreme/dist/css/dx.common.css";
import "devextreme/dist/css/dx.light.css";
import "./DxComponent.css";

import { Drawer } from "devextreme-react/drawer";

class DxComponent extends React.Component {
    constructor(props) {
        super(props);
    }
    render() {
        return (
            <React.Fragment>
                <Drawer
                    minSize={37}
                    height={250}
                    render={ () => <div style="width: 150px">Drawer content</div> } >
                    <div>View content</div>
                </Drawer>
            </React.Fragment>
        );
    }
}
export default DxComponent;
.dx-overlay-content {
    background-color: lightgray;
}
#view {
    margin-left: 10px;
    margin-top: 10px;
}
import React, { Component } from "react";

import DxComponent from "./components/DxComponent";

class App extends Component {
    render() {
        return (
            <div className="App">
                <DxComponent />
            </div>
        );
    }
}
export default App;
ASP.NET MVC Controls
_Layout.cshtml
Site.css
@(Html.DevExtreme().Drawer()
    .ID("layout-drawer")
    .Height(250)
    .MinSize(37)
    .Template(@<text><div style="width: 150px">Drawer content</div></text>)
    .Content(@<text><div id=".drawer-view-content">View content</div></text>)
)
.dx-overlay-content {
    background-color: lightgray;
}

.drawer-view-content {
    margin-left: 10px;
    margin-top: 10px;
}

If you run the code, you should see a partially visible Drawer and a view that displays View content.

Open and Close the Drawer

Depending on the library or framework you use, call the toggle() method or bind the opened option to a component property.

In the following code, a toolbar button outside the Drawer opens and closes it:

jQuery
index.js
index.html
style.css
$(function() {
    const drawer = $("#drawer").dxDrawer({ 
        // ... 
    }).dxDrawer("instance");
    $("#toolbar").dxToolbar({
        items: [{
            widget: "dxButton",
            location: "before",
            options: {
                icon: "menu",
                onClick: function() {
                    drawer.toggle();
                }
            }
        }]
    });
})
<div id="toolbar"></div>
<div id="drawer">
    <div id="view">View content</div>
</div>
/* ... */
#toolbar {
    background-color: rgba(191, 191, 191, .15);
    padding: 5px 10px;
}
.dx-toolbar-button .dx-button {
    background-color: rgba(191, 191, 191, -0.15);
    border: none;
}
.dx-toolbar-button > .dx-toolbar-item-content {
    margin-left: -7px;
}
Angular
app.component.html
app.component.ts
app.module.ts
app.component.css
<dx-toolbar id="toolbar">
    <dxi-item 
        widget="dxButton"
        [options]="buttonOptions"
        location="before">
    </dxi-item>
</dx-toolbar>
<dx-drawer ...
    [(opened)]="isDrawerOpen">
    <div>View content</div>
</dx-drawer>
import { Component } from "@angular/core";

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
})

export class AppComponent {
    isDrawerOpen: Boolean = false;
    buttonOptions: any;

    constructor() {
        this.buttonOptions = {
            icon: "menu",
            onClick: () => {
                this.isDrawerOpen = !this.isDrawerOpen;
            }
        };
    }
}
// ...
import { DxDrawerModule, DxToolbarModule } from "devextreme-angular";

@NgModule({
    declarations: [
        AppComponent
    ],
    imports: [
        // ...
        DxDrawerModule,
        DxToolbarModule,
    ],
    providers: [],
    bootstrap: [AppComponent]
})
export class AppModule { }
/* ... */
::ng-deep #toolbar {
    background-color: rgba(191, 191, 191, .15);
    padding: 5px 10px;
}
::ng-deep .dx-toolbar-button .dx-button {
    background-color: rgba(191, 191, 191, -0.15);
    border: none;
}
::ng-deep .dx-toolbar-button > .dx-toolbar-item-content {
    margin-left: -7px;
}
Vue
App.vue
<template>
    <div>
        <DxToolbar id="toolbar">
            <DxItem
                widget="dxButton"
                :options="buttonOptions"
                location="before"
            />
        </DxToolbar>
        <DxDrawer ...
            :opened.sync="isDrawerOpen">
            <!-- ... -->
        </DxDrawer>
    </div>
</template>

<script>
// ...
import DxToolbar, { DxItem } from 'devextreme-vue/toolbar';

export default {
    components: {
        // ...
        DxToolbar,
        DxItem
    },
    data() {
        return {
            buttonOptions: {
                icon: "menu",
                onClick: () => {
                    this.isDrawerOpen = !this.isDrawerOpen;
                }
            },
            isDrawerOpen: false
        };
    }
};
</script>

<style>
/* ... */
#toolbar {
    background-color: rgba(191, 191, 191, 0.15);
    padding: 5px 10px;
}
.dx-toolbar-button .dx-button {
    background-color: rgba(191, 191, 191, -0.15);
    border: none;
}
.dx-toolbar-button > .dx-toolbar-item-content {
    margin-left: -7px;
}
</style>
React
DxComponent.js
DxComponent.css
// ...
import { Drawer } from "devextreme-react/drawer";
import { Toolbar, Item } from "devextreme-react/toolbar";

class DxComponent extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            isDrawerOpen: false
        };
        this.buttonOptions = {
            icon: "menu",
            onClick: () => {
                this.setState({ isDrawerOpen: !this.state.isDrawerOpen })
            }
        };
    }
    render() {
        return (
            <React.Fragment>
                <Toolbar id="toolbar">
                    <Item 
                        widget="dxButton" 
                        options={this.buttonOptions} 
                        location="before" />
                </Toolbar>
                <Drawer ...
                    opened={this.state.isDrawerOpen} >
                    <div>View content</div>
                </Drawer>
            </React.Fragment>
        );
    }
}
export default DxComponent;
/* ... */
#toolbar {
    background-color: rgba(191, 191, 191, .15);
    padding: 5px 10px;
}
.dx-toolbar-button .dx-button {
    background-color: rgba(191, 191, 191, -0.15);
    border: none;
}
.dx-toolbar-button > .dx-toolbar-item-content {
    margin-left: -7px;
}
ASP.NET MVC Controls
_Layout.cshtml
Site.css
@(Html.DevExtreme().Toolbar()
    .ID("layout-toolbar")
    .Items(items =>{
        items.Add().Widget(w => w.Button()
            .Icon("menu")
            .OnClick("button_clickHandler")
        ).Location(ToolbarItemLocation.Before);
    })
)
@(Html.DevExtreme().Drawer()
    .ID("layout-drawer")
    // ...
)

<script type="text/javascript">
    function button_clickHandler() {
        const drawer = $("#layout-drawer").dxDrawer("instance");
        drawer.toggle();
    }
</script>
/* ... */
#layout-toolbar {
    background-color: rgba(191, 191, 191, .15);
    padding: 5px 10px;
}

#layout-toolbar .dx-toolbar-button .dx-button {
    background-color: rgba(191, 191, 191, -0.15);
    border: none;
}

#layout-toolbar .dx-toolbar-button > .dx-toolbar-item-content {
    margin-left: -7px;
}

Implement Navigation

The Drawer is designed to contain navigation items. If they should nest other items, use the TreeView widget to implement navigation. Otherwise, use the List.

These widgets provide the onSelectionChanged function in which we can implement the navigation logic. However, this function is executed only if you enable selection. In the TreeView, set the selectionMode to "single" and assign true to selectByClick; in the List, set the selectionMode to "single".

In this tutorial, we use the List:

jQuery
index.js
index.html
style.css
inbox.html
sent-mail.html
trash.html
spam.html
$(function() {
    // Loads the initial page
    $("#view" ).load( "./inbox.html" );

    const drawer = $("#drawer").dxDrawer({
        // ...
        template: function(e) {
            const $list = $("<div/>").dxList({
                items: [
                    { id: 1, text: "Inbox", icon: "message", filePath: "inbox" },
                    { id: 2, text: "Sent Mail", icon: "check", filePath: "sent-mail" },
                    { id: 3, text: "Trash", icon: "trash", filePath: "trash" },
                    { id: 4, text: "Spam", icon: "mention", filePath: "spam" }
                ],
                width: 200,
                selectionMode: "single",
                onSelectionChanged: function(e) {
                    $("#view").load( e.addedItems[0].filePath + ".html" );
                    drawer.hide();
                }
            });
            return $list;
        }
    }).dxDrawer("instance");
})
<div id="toolbar"></div>
<div id="drawer">
    <div id="view"></div>
</div>
/* ... */
.dx-list-item-icon {
    margin-right: 10px;
}
<div>Inbox</div>
<div>Sent Mail</div>
<div>Trash</div>
<div>Spam</div>
Angular
app.component.html
app.component.ts
app.component.css
app-routing.module.ts
app.module.ts
inbox.component.ts
sent-mail.component.ts
spam.component.ts
trash.component.ts
<dx-drawer ... >
    <div *dxTemplate="let data of 'template'">
        <dx-list
            [items]="navigation"
            [width]="200"
            selectionMode="single"
            (onSelectionChanged)="loadView($event)">
        </dx-list>
    </div>
    <div id="view"><router-outlet></router-outlet></div>
</dx-drawer>
import { Component } from "@angular/core";
import { Router } from "@angular/router";

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css'],
    providers: []
})

export class AppComponent {
    navigation: any;
    isDrawerOpen: Boolean = false;

    constructor(private router: Router) {
        this.navigation = [
            { id: 1, text: "Inbox", icon: "message", filePath: "inbox" },
            { id: 2, text: "Sent Mail", icon: "check", filePath: "sent-mail" },
            { id: 3, text: "Trash", icon: "trash", filePath: "trash" },
            { id: 4, text: "Spam", icon: "mention", filePath: "spam" }
        ];
    }
    loadView(e) {
        this.router.navigate([e.addedItems[0].filePath]);
        this.isDrawerOpen = false;
    }
}
/* ... */
::ng-deep .dx-list-item-icon {
    margin-right: 10px;
}
import { NgModule } from "@angular/core";
import { Routes, RouterModule } from "@angular/router";
import { InboxComponent } from "./views/inbox.component";
import { SentMailComponent } from "./views/sent-mail.component";
import { TrashComponent } from "./views/trash.component";
import { SpamComponent } from "./views/spam.component";

const routes: Routes = [
    { path: '', redirectTo: '/inbox', pathMatch: 'full' },
    { path: 'inbox', component: InboxComponent },
    { path: 'sent-mail', component: SentMailComponent },
    { path: 'trash', component: TrashComponent },
    { path: 'spam', component: SpamComponent },
];

@NgModule({
    imports: [RouterModule.forRoot(routes)],
    exports: [RouterModule],
    declarations: [
        InboxComponent,
        SentMailComponent,
        TrashComponent,
        SpamComponent
    ]
})
export class AppRoutingModule { }
import { AppRoutingModule } from "./app-routing.module";
import { DxDrawerModule, DxToolbarModule, DxListModule } from "devextreme-angular";
// ...
@NgModule({
    declarations: [
        AppComponent
    ],
    imports: [
        // ...
        AppRoutingModule,
        DxDrawerModule,
        DxToolbarModule,
        DxListModule
    ],
    providers: [],
    bootstrap: [AppComponent]
})
export class AppModule { }
import { Component } from "@angular/core";

@Component({
    selector: 'app-inbox',
    template: '<div>Inbox</div>'
})
export class InboxComponent { constructor() { } }
import { Component } from "@angular/core";

@Component({
    selector: 'app-sent-mail',
    template: '<div>Sent Mail</div>'
})
export class SentMailComponent { constructor() { } }
import { Component } from "@angular/core";

@Component({
    selector: 'app-spam',
    template: '<div>Spam</div>'
})
export class SpamComponent { constructor() { } }
import { Component } from "@angular/core";

@Component({
    selector: 'app-trash',
    template: '<div>Trash</div>'
})
export class TrashComponent { constructor() { } }
Vue
App.vue
NavigationList.vue
main.js
Inbox.vue
SentMail.vue
Spam.vue
Trash.vue
<template>
    <div>
        <!-- ... -->
        <DxDrawer ...
            template="list">
            <template #list>
                <NavigationList
                    @navigated="isDrawerOpen = false"
                />
            </template>
            <div id="view">
                <router-view></router-view>
            </div>
        </DxDrawer>
    </div>
</template>

<script>
// ...
import NavigationList from './components/NavigationList.vue';

export default {
    components: {
        // ...
        NavigationList
    },
    // ...
};
</script>

<style>
/* ... */
.dx-list-item-icon {
    margin-right: 10px;
}
</style>
<template>
    <DxList
        :width="200"
        selection-mode="single"
        :items="navigation"
        @selection-changed="loadView($event)"
    />
</template>
<script>
import { DxList } from "devextreme-vue/list";

export default {
    components: {
        DxList
    },
    data() {
        const navigation = [
            { id: 1, text: "Inbox", icon: "message", filePath: "inbox" },
            { id: 2, text: "Sent Mail", icon: "check", filePath: "sent-mail" },
            { id: 3, text: "Trash", icon: "trash", filePath: "trash" },
            { id: 4, text: "Spam", icon: "mention", filePath: "spam" }
        ];
        return {
            navigation
        };
    },
    methods: {
        loadView(e) {
            this.$router.push(e.addedItems[0].filePath);
            this.$emit('navigated');
        }
    }
}
</script>
import Vue from 'vue';
import VueRouter from 'vue-router';

import 'devextreme/dist/css/dx.common.css';
import 'devextreme/dist/css/dx.light.css';

import App from './App.vue';
import InboxComponent from "./components/Inbox.vue";
import SentMailComponent from "./components/SentMail.vue";
import TrashComponent from "./components/Trash.vue";
import SpamComponent from "./components/Spam.vue";

Vue.config.productionTip = false;

Vue.use(VueRouter);

const routes = [
    { path: "", redirect: "/inbox" },
    { path: "/inbox", component: InboxComponent },
    { path: "/sent-mail", component: SentMailComponent },
    { path: "/trash", component: TrashComponent },
    { path: "/spam", component: SpamComponent }
];

const router = new VueRouter({
    mode: "history",
    routes
});

new Vue({
    render: h => h(App),
    router
}).$mount('#app')
<template>
    <div>Inbox</div>
</template>

<script>
export default {}
</script>
<template>
    <div>Sent mail</div>
</template>

<script>
export default {}
</script>
<template>
    <div>Spam</div>
</template>

<script>
export default {}
</script>
<template>
    <div>Trash</div>
</template>

<script>
export default {}
</script>
React
DxComponent.js
NavigationList.js
history.js
DxComponent.css
Inbox.js
SentMail.js
Spam.js
Trash.js
// ...
import NavigationList from "./NavigationList";

import { Router, Route } from "react-router-dom";

import Inbox from "./views/Inbox";
import Trash from "./views/Trash";
import SentMail from "./views/SentMail";
import Spam from "./views/Spam";

import history from "./history";

class DxComponent extends React.Component {
    renderList = () => {
        const stateHandler = (newState) => this.setState(newState);
        return (
            <NavigationList stateHandler={stateHandler} />
        );
    }

    render() {
        return (
            <React.Fragment>
                <Drawer ...
                    render={this.renderList}>
                    <div id="view">
                        <Router history={history}>
                            <div>
                                <Route exact path="/" component={Inbox} />
                                <Route exact path="/inbox" component={Inbox} />
                                <Route exact path="/sent-mail" component={SentMail} />
                                <Route exact path="/spam" component={Spam} />
                                <Route exact path="/trash" component={Trash} />
                            </div>
                        </Router>
                    </div>
                </Drawer>
            </React.Fragment>
        );
    }
}
export default DxComponent;
import React from "react";
import List from "devextreme-react/list";
import history from "./history";

const navigation = [
    { id: 1, text: "Inbox", icon: "message", filePath: "inbox" },
    { id: 2, text: "Sent Mail", icon: "check", filePath: "sent-mail" },
    { id: 3, text: "Trash", icon: "trash", filePath: "trash" },
    { id: 4, text: "Spam", icon: "mention", filePath: "spam" }
];

class NavigationList extends React.PureComponent {
    loadView(e) {
        history.push(e.addedItems[0].filePath);
        this.props.stateHandler({ isDrawerOpen: false });
    }
    render() {
        return (
            <React.Fragment>
                <List
                    items={navigation}
                    width={200} 
                    selectionMode="single"
                    onSelectionChanged={this.loadView} />
            </React.Fragment>
        );
    }
}
export default NavigationList;
import { createBrowserHistory } from "history";

export default createBrowserHistory()
/* ... */
.dx-list-item-icon {
    margin-right: 10px;
}
import React from "react";

class Inbox extends React.Component {
    render() {
        return (
            <div>Inbox</div>
        );
    }
}
export default Inbox;
import React from "react";

class SentMail extends React.Component {
    render() {
        return (
            <div>Sent Mail</div>
        );
    }
}
export default SentMail;
import React from "react";

class Spam extends React.Component {
    render() {
        return (
            <div>Spam</div>
        );
    }
}
export default Spam;
import React from "react";

class Trash extends React.Component {
    render() {
        return (
            <div>Trash</div>
        );
    }
}
export default Trash;
ASP.NET MVC Controls
_Layout.cshtml
HomeController.cs
Site.css
Index.cshtml
Deleted.cshtml
Sent.cshtml
Spam.cshtml
@(Html.DevExtreme().Toolbar()
    // ...
)
@(Html.DevExtreme().Drawer()
    .ID("layout-drawer")   
    .Template(@<text>
        @(Html.DevExtreme().List()
            .Width(200)
            .OnInitialized("list_onInitialized")
            .Items(items => {
                items.Add().Text("Inbox").Icon("message").Option("path", @Url.Action("Index"));
                items.Add().Text("Sent Mail").Icon("check").Option("path", @Url.Action("Sent"));
                items.Add().Text("Deleted").Icon("trash").Option("path", @Url.Action("Deleted"));
                items.Add().Text("Spam").Icon("mention").Option("path", @Url.Action("Spam"));
            })
            .KeyExpr("path")
            .SelectionMode(ListSelectionMode.Single)
            .OnSelectionChanged("list_onSelectionChanged")
        )
    </text>)
    .Content(@<text>@RenderBody()</text>)
)

<script type="text/javascript">
    function button_clickHandler() {
        // ...
        sessionStorage.setItem("isDrawerOpen", JSON.stringify(drawer.option("opened")));
    }

    function list_onSelectionChanged(e) {
        document.location.pathname = e.addedItems[0].path;
        $("#layout-drawer").dxDrawer("hide");
    }

    function list_onInitialized(e) {
        const t = "@Url.Action()";
        e.component.option("selectedItemKeys", [ "@Url.Action()" ])
    }
</script>
using System.Web.Mvc;

namespace DevExtremeApp.Controllers {
    public class HomeController : Controller {
        public ActionResult Index() {
            return View();
        }

        public ActionResult Deleted() {
            return View();
        }

        public ActionResult Sent() {
            return View();
        }

        public ActionResult Spam() {
            return View();
        }
    }
}
/* ... */
#layout-toolbar .dx-list-item-icon {
    margin-right: 10px;
}
<div class="drawer-view-content">Inbox</div>
<div class="drawer-view-content">Deleted</div>
<div class="drawer-view-content">Sent</div>
<div class="drawer-view-content">Spam</div>

Run the code, open the Drawer, and click its items to change the views.

Configure the Reveal Behavior

When you open the Drawer, it can slide in or expand from the closed position. Use the revealMode option to specify this behavior.

jQuery
index.js
$(function() {
    const drawer = $("#drawer").dxDrawer({
        // ...
        revealMode: "expand"
    }).dxDrawer("instance");
})
Angular
app.component.html
<dx-drawer ...
    revealMode="expand">
</dx-drawer>
Vue
App.vue
<template>
    <div>
        <!-- ... -->
        <DxDrawer ...
            reveal-mode="expand">
            <!-- ... -->
        </DxDrawer>
    </div>
</template>

<script>
// ...
</script>
React
DxComponent.js
// ...
class DxComponent extends React.Component {
    // ...
    render() {
        return (
            <React.Fragment>
                <Drawer ...
                    revealMode="expand" >
                </Drawer>
            </React.Fragment>
        );
    }
}
export default DxComponent;
ASP.NET MVC Controls
_Layout.cshtml
@(Html.DevExtreme().Drawer()
    .ID("layout-drawer")   
    .RevealMode(DrawerRevealMode.Expand)
)

Run the code and open the Drawer. You should see that the widget gets wider, but its content stays in place, creating an impression that the Drawer expands.

Configure Interaction with the View

When the Drawer opens, it can overlap, shrink, or partially displace the view, depending on the openedStateMode option:

jQuery
index.js
$(function() {
    const drawer = $("#drawer").dxDrawer({
        // ...
        openedStateMode: "overlap"
    }).dxDrawer("instance");
})
Angular
app.component.html
<dx-drawer ...
    openedStateMode="overlap">
</dx-drawer>
Vue
App.vue
<template>
    <div>
        <!-- ... -->
        <DxDrawer ...
            opened-state-mode="overlap">
            <!-- ... -->
        </DxDrawer>
    </div>
</template>

<script>
// ...
</script>
React
DxComponent.js
// ...
class DxComponent extends React.Component {
    // ...
    render() {
        return (
            <React.Fragment>
                <Drawer ...
                    openedStateMode="overlap" >
                </Drawer>
            </React.Fragment>
        );
    }
}
export default DxComponent;
ASP.NET MVC Controls
_Layout.cshtml
@(Html.DevExtreme().Drawer()
    .ID("layout-drawer")   
    .OpenedStateMode(DrawerOpenedStateMode.Overlap)
)

Run the code, open the Drawer and you should see that it overlaps the view's text.

Change the Position

You can use the position option to anchor the Drawer to any side of the view. In this tutorial, the Drawer is in its default position (left).

You have configured basic Drawer features. For more information about this widget, explore the following resources: