diff --git a/angular/src/directives/proxies-list.txt b/angular/src/directives/proxies-list.txt
index 0f06d58842e..ca7119370bb 100644
--- a/angular/src/directives/proxies-list.txt
+++ b/angular/src/directives/proxies-list.txt
@@ -19,6 +19,7 @@ d.IonApp,
d.IonCol,
d.IonContent,
d.IonDatetime,
+ d.IonDrawer,
d.IonFab,
d.IonFabButton,
d.IonFabList,
diff --git a/angular/src/directives/proxies.ts b/angular/src/directives/proxies.ts
index 46b57543cda..360f263af51 100644
--- a/angular/src/directives/proxies.ts
+++ b/angular/src/directives/proxies.ts
@@ -210,6 +210,24 @@ export class IonDatetime {
}
}
+export declare interface IonDrawer extends Components.IonDrawer {}
+@ProxyCmp({inputs: ['mode', 'options', 'presentDefault'], 'methods': ['update', 'present', 'destroy', 'moveToBreak', 'hide', 'isHidden', 'getDrawer']})
+@Component({ selector: 'ion-drawer', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['mode', 'options', 'presentDefault'] })
+export class IonDrawer {
+ ionDrawerDidDismiss!: EventEmitter;
+ ionDrawerWillDismiss!: EventEmitter;
+ ionDrawerTransitionEnd!: EventEmitter;
+ ionDrawerWillPresent!: EventEmitter;
+ ionDrawerDragStart!: EventEmitter;
+ ionDrawerOnDrag!: EventEmitter;
+ protected el: HTMLElement;
+ constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
+ c.detach();
+ this.el = r.nativeElement;
+ proxyOutputs(this, this.el, ['ionDrawerDidDismiss', 'ionDrawerWillDismiss', 'ionDrawerTransitionEnd', 'ionDrawerWillPresent', 'ionDrawerDragStart', 'ionDrawerOnDrag']);
+ }
+}
+
export declare interface IonFab extends Components.IonFab {}
@ProxyCmp({inputs: ['activated', 'edge', 'horizontal', 'vertical'], 'methods': ['close']})
@Component({ selector: 'ion-fab', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['activated', 'edge', 'horizontal', 'vertical'] })
diff --git a/core/api.txt b/core/api.txt
index 6469dd119b0..9da37693baa 100644
--- a/core/api.txt
+++ b/core/api.txt
@@ -320,7 +320,7 @@ ion-datetime,prop,monthShortNames,string | string[] | undefined,undefined,false,
ion-datetime,prop,monthValues,number | number[] | string | undefined,undefined,false,false
ion-datetime,prop,name,string,this.inputId,false,false
ion-datetime,prop,pickerFormat,string | undefined,undefined,false,false
-ion-datetime,prop,pickerOptions,undefined | { columns?: PickerColumn[] | undefined; buttons?: PickerButton[] | undefined; cssClass?: string | string[] | undefined; backdropDismiss?: boolean | undefined; animated?: boolean | undefined; mode?: "ios" | "md" | undefined; keyboardClose?: boolean | undefined; id?: string | undefined; enterAnimation?: AnimationBuilder | undefined; leaveAnimation?: AnimationBuilder | undefined; },undefined,false,false
+ion-datetime,prop,pickerOptions,undefined | { columns?: PickerColumn[] | undefined; buttons?: PickerButton[] | undefined; cssClass?: string | string[] | undefined; showBackdrop?: boolean | undefined; backdropDismiss?: boolean | undefined; animated?: boolean | undefined; mode?: "ios" | "md" | undefined; keyboardClose?: boolean | undefined; id?: string | undefined; enterAnimation?: AnimationBuilder | undefined; leaveAnimation?: AnimationBuilder | undefined; },undefined,false,false
ion-datetime,prop,placeholder,null | string | undefined,undefined,false,false
ion-datetime,prop,readonly,boolean,false,false,false
ion-datetime,prop,value,null | string | undefined,undefined,false,false
@@ -336,6 +336,24 @@ ion-datetime,css-prop,--padding-start
ion-datetime,css-prop,--padding-top
ion-datetime,css-prop,--placeholder-color
+ion-drawer,none
+ion-drawer,prop,mode,"ios" | "md",undefined,false,false
+ion-drawer,prop,options,any,{},false,false
+ion-drawer,prop,presentDefault,boolean,false,false,false
+ion-drawer,method,destroy,destroy(conf?: {}) => Promise
+ion-drawer,method,getDrawer,getDrawer() => Promise
+ion-drawer,method,hide,hide() => Promise
+ion-drawer,method,isHidden,isHidden() => Promise
+ion-drawer,method,moveToBreak,moveToBreak(val: "top" | "middle" | "bottom") => Promise
+ion-drawer,method,present,present(conf?: {}) => Promise
+ion-drawer,method,update,update() => Promise
+ion-drawer,event,ionDrawerDidDismiss,void,true
+ion-drawer,event,ionDrawerDragStart,void,true
+ion-drawer,event,ionDrawerOnDrag,void,true
+ion-drawer,event,ionDrawerTransitionEnd,void,true
+ion-drawer,event,ionDrawerWillDismiss,void,true
+ion-drawer,event,ionDrawerWillPresent,void,true
+
ion-fab,shadow
ion-fab,prop,activated,boolean,false,false,false
ion-fab,prop,edge,boolean,false,false,false
diff --git a/core/package.json b/core/package.json
index b4a2ba43bb0..b7c064c868d 100644
--- a/core/package.json
+++ b/core/package.json
@@ -42,6 +42,7 @@
"@types/swiper": "4.4.4",
"aws-sdk": "^2.497.0",
"clean-css-cli": "^4.1.11",
+ "cupertino-pane": "^1.0.9",
"domino": "^2.1.3",
"fs-extra": "^8.0.1",
"jest": "24.9.0",
diff --git a/core/src/components.d.ts b/core/src/components.d.ts
index a548e96d64d..6deb45793bb 100644
--- a/core/src/components.d.ts
+++ b/core/src/components.d.ts
@@ -708,6 +708,48 @@ export namespace Components {
*/
'yearValues'?: number[] | number | string;
}
+ interface IonDrawer {
+ /**
+ * Remove pane from DOM and clear styles
+ */
+ 'destroy': (conf?: {}) => Promise;
+ /**
+ * Use this to access the full Drawer API.
+ */
+ 'getDrawer': () => Promise;
+ /**
+ * Dissappear pane from screen, still keep pane in DOM
+ */
+ 'hide': () => Promise;
+ /**
+ * Determinate if drawer position was moved out of screen, but pane still exist in DOM.
+ */
+ 'isHidden': () => Promise;
+ /**
+ * The mode determines which platform styles to use.
+ */
+ 'mode'?: "ios" | "md";
+ /**
+ * Will change pane position with animation to selected breakpoint
+ */
+ 'moveToBreak': (val: "top" | "middle" | "bottom") => Promise;
+ /**
+ * Options to pass to the drawer instance. See https://github.com/roman-rr/cupertino-pane/ for valid options
+ */
+ 'options': any;
+ /**
+ * Render and show Drawer pane from ion-drawer component
+ */
+ 'present': (conf?: {}) => Promise;
+ /**
+ * If `true`, show the drawer right after component loaded.
+ */
+ 'presentDefault': boolean;
+ /**
+ * Update the underlying Drawer implementation.
+ */
+ 'update': () => Promise;
+ }
interface IonFab {
/**
* If `true`, both the `ion-fab-button` and all `ion-fab-list` inside `ion-fab` will become active. That means `ion-fab-button` will become a `close` icon and `ion-fab-list` will become visible.
@@ -2787,6 +2829,12 @@ declare global {
new (): HTMLIonDatetimeElement;
};
+ interface HTMLIonDrawerElement extends Components.IonDrawer, HTMLStencilElement {}
+ var HTMLIonDrawerElement: {
+ prototype: HTMLIonDrawerElement;
+ new (): HTMLIonDrawerElement;
+ };
+
interface HTMLIonFabElement extends Components.IonFab, HTMLStencilElement {}
var HTMLIonFabElement: {
prototype: HTMLIonFabElement;
@@ -3214,6 +3262,7 @@ declare global {
'ion-col': HTMLIonColElement;
'ion-content': HTMLIonContentElement;
'ion-datetime': HTMLIonDatetimeElement;
+ 'ion-drawer': HTMLIonDrawerElement;
'ion-fab': HTMLIonFabElement;
'ion-fab-button': HTMLIonFabButtonElement;
'ion-fab-list': HTMLIonFabListElement;
@@ -3938,6 +3987,44 @@ declare namespace LocalJSX {
*/
'yearValues'?: number[] | number | string;
}
+ interface IonDrawer {
+ /**
+ * The mode determines which platform styles to use.
+ */
+ 'mode'?: "ios" | "md";
+ /**
+ * Emitted after pane will dissapeared
+ */
+ 'onIonDrawerDidDismiss'?: (event: CustomEvent) => void;
+ /**
+ * Emitted when detect user drag event on pane
+ */
+ 'onIonDrawerDragStart'?: (event: CustomEvent) => void;
+ /**
+ * Emitted executes on each new pane position
+ */
+ 'onIonDrawerOnDrag'?: (event: CustomEvent) => void;
+ /**
+ * Emitted after pane will present
+ */
+ 'onIonDrawerTransitionEnd'?: (event: CustomEvent) => void;
+ /**
+ * Emitted before pane will dissapeared
+ */
+ 'onIonDrawerWillDismiss'?: (event: CustomEvent) => void;
+ /**
+ * Emitted before panel will present
+ */
+ 'onIonDrawerWillPresent'?: (event: CustomEvent) => void;
+ /**
+ * Options to pass to the drawer instance. See https://github.com/roman-rr/cupertino-pane/ for valid options
+ */
+ 'options'?: any;
+ /**
+ * If `true`, show the drawer right after component loaded.
+ */
+ 'presentDefault'?: boolean;
+ }
interface IonFab {
/**
* If `true`, both the `ion-fab-button` and all `ion-fab-list` inside `ion-fab` will become active. That means `ion-fab-button` will become a `close` icon and `ion-fab-list` will become visible.
@@ -5846,6 +5933,7 @@ declare namespace LocalJSX {
'ion-col': IonCol;
'ion-content': IonContent;
'ion-datetime': IonDatetime;
+ 'ion-drawer': IonDrawer;
'ion-fab': IonFab;
'ion-fab-button': IonFabButton;
'ion-fab-list': IonFabList;
@@ -5942,6 +6030,7 @@ declare module "@stencil/core" {
'ion-col': LocalJSX.IonCol & JSXBase.HTMLAttributes;
'ion-content': LocalJSX.IonContent & JSXBase.HTMLAttributes;
'ion-datetime': LocalJSX.IonDatetime & JSXBase.HTMLAttributes;
+ 'ion-drawer': LocalJSX.IonDrawer & JSXBase.HTMLAttributes;
'ion-fab': LocalJSX.IonFab & JSXBase.HTMLAttributes;
'ion-fab-button': LocalJSX.IonFabButton & JSXBase.HTMLAttributes;
'ion-fab-list': LocalJSX.IonFabList & JSXBase.HTMLAttributes;
diff --git a/core/src/components/drawer/drawer.ios.scss b/core/src/components/drawer/drawer.ios.scss
new file mode 100644
index 00000000000..37a478a98b2
--- /dev/null
+++ b/core/src/components/drawer/drawer.ios.scss
@@ -0,0 +1,4 @@
+@import "./drawer";
+
+// iOS Drawer
+// --------------------------------------------------
\ No newline at end of file
diff --git a/core/src/components/drawer/drawer.md.scss b/core/src/components/drawer/drawer.md.scss
new file mode 100644
index 00000000000..0cef44dca2e
--- /dev/null
+++ b/core/src/components/drawer/drawer.md.scss
@@ -0,0 +1,30 @@
+@import "./drawer";
+
+// Material Design Drawer
+// --------------------------------------------------
+/* stylelint-disable */
+.drawer-md .pane {
+ border-top-left-radius: 12px !important;
+ border-top-right-radius: 12px !important;
+
+ box-shadow: 0 3px 5px -1px rgba(184, 153, 153, 0.2),
+ 0 6px 10px 0 rgba(0,0,0,.17),
+ 0 1px 18px 0 rgba(0,0,0,.2) !important;
+
+ .draggable {
+ @include margin(3px, 0, 3px, 0);
+ }
+
+ .draggable .move {
+ width: 28px !important;
+
+ background: rgba(192, 192, 192, 0.55) !important;
+ }
+
+ .close-button {
+ top: 10px !important;
+ right: 10px !important;
+
+ background: #e0e0e0 !important;
+ }
+}
diff --git a/core/src/components/drawer/drawer.scss b/core/src/components/drawer/drawer.scss
new file mode 100644
index 00000000000..83e9cf8237e
--- /dev/null
+++ b/core/src/components/drawer/drawer.scss
@@ -0,0 +1,13 @@
+@import "../../themes/ionic.globals.md";
+
+// Drawer
+// --------------------------------------------------
+ion-drawer {
+ @include padding(0, 20px, 0, 20px);
+
+ display: none;
+}
+
+.pane > ion-drawer {
+ display: block;
+}
\ No newline at end of file
diff --git a/core/src/components/drawer/drawer.tsx b/core/src/components/drawer/drawer.tsx
new file mode 100644
index 00000000000..7f5c5de2595
--- /dev/null
+++ b/core/src/components/drawer/drawer.tsx
@@ -0,0 +1,218 @@
+import { Component, ComponentInterface, Element, Event, EventEmitter, Host, Method, Prop, Watch, h } from '@stencil/core';
+
+import { getIonMode } from '../../global/ionic-global';
+
+/**
+ * @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
+ */
+@Component({
+ tag: 'ion-drawer',
+ styleUrls: {
+ ios: 'drawer.ios.scss',
+ md: 'drawer.md.scss'
+ }
+})
+export class Drawer implements ComponentInterface {
+
+ private drawerReady = false;
+ private readyDrawer!: (drawer: any) => void;
+ private drawer: Promise = new Promise(resolve => { this.readyDrawer = resolve; });
+
+ @Element() el!: HTMLIonDrawerElement;
+
+ /**
+ * Options to pass to the drawer instance.
+ * See https://github.com/roman-rr/cupertino-pane/ for valid options
+ */
+ @Prop() options: any = {}; // DrawerOptions;
+
+ @Watch('options')
+ async optionsChanged() {
+ if (this.drawerReady) {
+ const drawer = await this.getDrawer();
+ Object.assign(drawer.settings, this.options);
+ console.log(drawer.settings);
+ await this.update();
+ }
+ }
+
+ /**
+ * If `true`, show the drawer right after component loaded.
+ */
+ @Prop() presentDefault = false;
+
+ /**
+ * Emitted after pane will dissapeared
+ */
+ @Event() ionDrawerDidDismiss!: EventEmitter;
+
+ /**
+ * Emitted before pane will dissapeared
+ */
+ @Event() ionDrawerWillDismiss!: EventEmitter;
+
+ /**
+ * Emitted after pane will present
+ */
+ @Event() ionDrawerTransitionEnd!: EventEmitter;
+
+ /**
+ * Emitted before panel will present
+ */
+ @Event() ionDrawerWillPresent!: EventEmitter;
+
+ /**
+ * Emitted when detect user drag event on pane
+ */
+ @Event() ionDrawerDragStart!: EventEmitter;
+
+ /**
+ * Emitted executes on each new pane position
+ */
+ @Event() ionDrawerOnDrag!: EventEmitter;
+
+ componentDidLoad() {
+ this.el.componentOnReady().then(() => this.initDrawer());
+ }
+
+ /**
+ * Update the underlying Drawer implementation.
+ */
+ @Method()
+ async update() {
+ const drawer = await this.getDrawer();
+ drawer.destroy();
+ drawer.present();
+ }
+
+ /**
+ * Render and show Drawer pane from ion-drawer component
+ */
+ @Method()
+ async present(conf: {} = { animate: false }) {
+ const drawer = await this.getDrawer();
+ drawer.present(conf);
+ this.drawerReady = true;
+ }
+
+ /**
+ * Remove pane from DOM and clear styles
+ */
+ @Method()
+ async destroy(conf: {} = { animate: false }) {
+ if (this.drawerReady) {
+ const drawer = await this.getDrawer();
+ console.log('13232345234v2 23452345 ', drawer);
+ drawer.destroy(conf);
+ this.drawerReady = false;
+ }
+ }
+
+ /**
+ * Will change pane position with animation to selected breakpoint
+ */
+ @Method()
+ async moveToBreak(val: 'top' | 'middle' | 'bottom') {
+ const drawer = await this.getDrawer();
+ try {
+ drawer.moveToBreak(val);
+ } catch (err) {
+ console.warn('Drawer is not present');
+ }
+ }
+
+ /**
+ * Dissappear pane from screen, still keep pane in DOM
+ */
+ @Method()
+ async hide() {
+ const drawer = await this.getDrawer();
+ try {
+ drawer.hide();
+ } catch (err) {
+ console.warn('Drawer is not present');
+ }
+ }
+
+ /**
+ * Determinate if drawer position was moved out of screen, but pane still exist in DOM.
+ */
+ @Method()
+ async isHidden(): Promise {
+ const drawer = await this.getDrawer();
+ try {
+ return drawer.isHidden();
+ } catch (err) {
+ console.warn('Drawer is not present');
+ return null;
+ }
+ }
+
+ /**
+ * Use this to access the full Drawer API.
+ */
+ @Method()
+ async getDrawer(): Promise {
+ return this.drawer;
+ }
+
+ private async initDrawer() {
+ const finalOptions = this.normalizeOptions();
+
+ // init drawer core
+ const { CupertinoPane } = await import('cupertino-pane');
+ const drawer = new CupertinoPane('ion-drawer', finalOptions);
+ this.readyDrawer(drawer);
+ if (this.presentDefault) {
+ this.present();
+ this.drawerReady = true;
+ }
+ }
+
+ private get deviceOffset() {
+ // Calc device offsets (statusbars, bottom, top, iPhone X, XS etc.)
+ const sat = getComputedStyle(document.documentElement).getPropertyValue('--ion-safe-area-top');
+ const sab = getComputedStyle(document.documentElement).getPropertyValue('--ion-safe-area-bottom');
+ const offset = parseFloat(sat.replace('px', '')) + parseFloat(sab.replace('px', ''));
+ return offset;
+ }
+
+ private normalizeOptions(): any {
+ // Base options, can be changed
+ // TODO Add interface DrawerOptions
+ const drawerOptions: any = {};
+
+ // Events
+ const eventOptions: any = {
+ onDidDismiss: this.ionDrawerDidDismiss.emit,
+ onWillDismiss: this.ionDrawerWillDismiss.emit,
+ onDidPresent: this.ionDrawerTransitionEnd.emit,
+ onWillPresent: this.ionDrawerWillPresent.emit,
+ onDragStart: this.ionDrawerDragStart.emit,
+ onDrag: this.ionDrawerOnDrag.emit
+ };
+
+ if (this.options.topperOverflowOffset) {
+ this.options.topperOverflowOffset += this.deviceOffset;
+ } else {
+ this.options.topperOverflowOffset = this.deviceOffset;
+ }
+
+ // Merge the base, user options, and events together then pas to swiper
+ return { ...drawerOptions, ...this.options, ...eventOptions };
+ }
+
+ render() {
+ const mode = getIonMode(this);
+ return (
+
+
+
+ );
+ }
+}
diff --git a/core/src/components/drawer/readme.md b/core/src/components/drawer/readme.md
new file mode 100644
index 00000000000..a212d6f5a9d
--- /dev/null
+++ b/core/src/components/drawer/readme.md
@@ -0,0 +1,233 @@
+# ion-drawer
+
+The Drawer component is a lightweight drawer slide-over pane. For modern progressive applications.
+
+Adopted from Cupertino Pane:
+Modern slide-over pane drawer with touch technologies. Right like in Apple Maps, Apple Stocks, Apple Music and other modern apps.
+
+https://github.com/roman-rr/cupertino-pane/
+
+Copyright 2020, Roman Antonov
+
+Licensed under MIT
+
+
+
+
+## Usage
+
+### Angular
+
+```typescript
+import { Component, OnInit } from '@angular/core';
+import { IonDrawer } from '@ionic/angular';
+
+@Component({
+ selector: 'drawer-example',
+ template: `
+
+ Header
+ Content
+
+ `
+})
+export class DrawerExample implements OnInit {
+ @ViewChild('pane', {read: IonDrawer, static: false}) drawer: IonDrawer;
+
+ // Optional parameters to pass to the drawer instance. See https://github.com/roman-rr/cupertino-pane/ for valid options.
+ public drawerOpts = {
+ showDraggable: true,
+ breaks: {
+ top: { enabled: false, offset: 0 },
+ middle: { enabled: true, offset: 0 },
+ bottom: { enabled: true, offset: 0 },
+ }
+ };
+
+ constructor() {}
+
+ hideDrawer() {
+ drawer.hide();
+ }
+}
+```
+
+
+### Javascript
+
+```html
+
+ Header
+ Content
+
+```
+
+```javascript
+var drawer = document.querySelector('ion-drawer');
+
+// Optional parameters to pass to the drawer instance. See https://github.com/roman-rr/cupertino-pane/ for valid options.
+drawer.options = {
+ showDraggable: true,
+ breaks: {
+ top: { enabled: false, offset: 0 },
+ middle: { enabled: true, offset: 0 },
+ bottom: { enabled: true, offset: 0 },
+ }
+}
+```
+
+
+### React
+
+```tsx
+import React from 'react';
+import { IonDrawer, IonContent } from '@ionic/react';
+
+// Optional parameters to pass to the drawer instance. See https://github.com/roman-rr/cupertino-pane/ for valid options.
+const drawerOpts = {
+ showDraggable: true,
+ breaks: {
+ top: { enabled: false, offset: 0 },
+ middle: { enabled: true, offset: 0 },
+ bottom: { enabled: true, offset: 0 },
+ }
+};
+
+export const DrawerExample: React.FC = () => (
+
+
+ Header
+ Content
+
+
+);
+```
+
+
+### Vue
+
+```html
+
+
+ Header
+ Content
+
+
+
+
+```
+
+
+
+## Properties
+
+| Property | Attribute | Description | Type | Default |
+| ---------------- | ----------------- | --------------------------------------------------------------------------------------------------------- | --------------- | ----------- |
+| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` |
+| `options` | `options` | Options to pass to the drawer instance. See https://github.com/roman-rr/cupertino-pane/ for valid options | `any` | `{}` |
+| `presentDefault` | `present-default` | If `true`, show the drawer right after component loaded. | `boolean` | `false` |
+
+
+## Events
+
+| Event | Description | Type |
+| ------------------------ | ------------------------------------------- | ------------------- |
+| `ionDrawerDidDismiss` | Emitted after pane will dissapeared | `CustomEvent` |
+| `ionDrawerDragStart` | Emitted when detect user drag event on pane | `CustomEvent` |
+| `ionDrawerOnDrag` | Emitted executes on each new pane position | `CustomEvent` |
+| `ionDrawerTransitionEnd` | Emitted after pane will present | `CustomEvent` |
+| `ionDrawerWillDismiss` | Emitted before pane will dissapeared | `CustomEvent` |
+| `ionDrawerWillPresent` | Emitted before panel will present | `CustomEvent` |
+
+
+## Methods
+
+### `destroy(conf?: {}) => Promise`
+
+Remove pane from DOM and clear styles
+
+#### Returns
+
+Type: `Promise`
+
+
+
+### `getDrawer() => Promise`
+
+Use this to access the full Drawer API.
+
+#### Returns
+
+Type: `Promise`
+
+
+
+### `hide() => Promise`
+
+Dissappear pane from screen, still keep pane in DOM
+
+#### Returns
+
+Type: `Promise`
+
+
+
+### `isHidden() => Promise`
+
+Determinate if drawer position was moved out of screen, but pane still exist in DOM.
+
+#### Returns
+
+Type: `Promise`
+
+
+
+### `moveToBreak(val: "top" | "middle" | "bottom") => Promise`
+
+Will change pane position with animation to selected breakpoint
+
+#### Returns
+
+Type: `Promise`
+
+
+
+### `present(conf?: {}) => Promise`
+
+Render and show Drawer pane from ion-drawer component
+
+#### Returns
+
+Type: `Promise`
+
+
+
+### `update() => Promise`
+
+Update the underlying Drawer implementation.
+
+#### Returns
+
+Type: `Promise`
+
+
+
+
+----------------------------------------------
+
+*Built with [StencilJS](https://stenciljs.com/)*
diff --git a/core/src/components/drawer/test/basic/e2e.ts b/core/src/components/drawer/test/basic/e2e.ts
new file mode 100644
index 00000000000..fdd41ddc055
--- /dev/null
+++ b/core/src/components/drawer/test/basic/e2e.ts
@@ -0,0 +1,10 @@
+import { newE2EPage } from '@stencil/core/testing';
+
+test('drawer: basic', async () => {
+ const page = await newE2EPage({
+ url: '/src/components/drawer/test/basic?ionic:_testing=true'
+ });
+
+ const compare = await page.compareScreenshot();
+ expect(compare).toMatchScreenshot();
+});
diff --git a/core/src/components/drawer/test/basic/index.html b/core/src/components/drawer/test/basic/index.html
new file mode 100644
index 00000000000..75788d3fc60
--- /dev/null
+++ b/core/src/components/drawer/test/basic/index.html
@@ -0,0 +1,121 @@
+
+
+
+
+
+ Drawer - Basic
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Header
+ Content
+
+
+ Present Drawer
+ Destroy Drawer
+
+ Hide Drawer
+ Drawer is hidden
+
+ Set Top
+ Set Moddle
+ Set bottom
+
+ Enable free mode
+ Close on bottom break
+ Bottom + Middle breaks
+
+
+
+
+
+
+
diff --git a/core/src/components/drawer/usage/angular.md b/core/src/components/drawer/usage/angular.md
new file mode 100644
index 00000000000..4e23806500b
--- /dev/null
+++ b/core/src/components/drawer/usage/angular.md
@@ -0,0 +1,33 @@
+```typescript
+import { Component, OnInit } from '@angular/core';
+import { IonDrawer } from '@ionic/angular';
+
+@Component({
+ selector: 'drawer-example',
+ template: `
+
+ Header
+ Content
+
+ `
+})
+export class DrawerExample implements OnInit {
+ @ViewChild('pane', {read: IonDrawer, static: false}) drawer: IonDrawer;
+
+ // Optional parameters to pass to the drawer instance. See https://github.com/roman-rr/cupertino-pane/ for valid options.
+ public drawerOpts = {
+ showDraggable: true,
+ breaks: {
+ top: { enabled: false, offset: 0 },
+ middle: { enabled: true, offset: 0 },
+ bottom: { enabled: true, offset: 0 },
+ }
+ };
+
+ constructor() {}
+
+ hideDrawer() {
+ drawer.hide();
+ }
+}
+```
diff --git a/core/src/components/drawer/usage/javascript.md b/core/src/components/drawer/usage/javascript.md
new file mode 100644
index 00000000000..f84f57903b9
--- /dev/null
+++ b/core/src/components/drawer/usage/javascript.md
@@ -0,0 +1,20 @@
+```html
+
+ Header
+ Content
+
+```
+
+```javascript
+var drawer = document.querySelector('ion-drawer');
+
+// Optional parameters to pass to the drawer instance. See https://github.com/roman-rr/cupertino-pane/ for valid options.
+drawer.options = {
+ showDraggable: true,
+ breaks: {
+ top: { enabled: false, offset: 0 },
+ middle: { enabled: true, offset: 0 },
+ bottom: { enabled: true, offset: 0 },
+ }
+}
+```
diff --git a/core/src/components/drawer/usage/react.md b/core/src/components/drawer/usage/react.md
new file mode 100644
index 00000000000..ecca65b3bf3
--- /dev/null
+++ b/core/src/components/drawer/usage/react.md
@@ -0,0 +1,23 @@
+```tsx
+import React from 'react';
+import { IonDrawer, IonContent } from '@ionic/react';
+
+// Optional parameters to pass to the drawer instance. See https://github.com/roman-rr/cupertino-pane/ for valid options.
+const drawerOpts = {
+ showDraggable: true,
+ breaks: {
+ top: { enabled: false, offset: 0 },
+ middle: { enabled: true, offset: 0 },
+ bottom: { enabled: true, offset: 0 },
+ }
+};
+
+export const DrawerExample: React.FC = () => (
+
+
+ Header
+ Content
+
+
+);
+```
\ No newline at end of file
diff --git a/core/src/components/drawer/usage/vue.md b/core/src/components/drawer/usage/vue.md
new file mode 100644
index 00000000000..a7dcaf2a9da
--- /dev/null
+++ b/core/src/components/drawer/usage/vue.md
@@ -0,0 +1,25 @@
+```html
+
+
+ Header
+ Content
+
+
+
+
+```