A pure Js snappable, scrollable, customisable bottomsheet!
- Works as a bottomsheet in mobile and as a modal or sidesheet in web.
- Supports multiple snap points.
- Uses spring animations.
- Supports stacking of bottomsheets.
- Is scrollable at the last snappoint.
- Supports dynamic content.
- Sidesheets are resizable.
- Use Gesture: https://use-gesture.netlify.app/docs/#vanilla-javascript
- Anime js: https://animejs.com/
npm:
npm i js-bottomsheet
Here's a simple usage of the bottomsheet with static content.
HTML:
<button id="trigger-1" data-bottomsheet-id='bottomsheet-1'>click</button>
<div id="bottomsheet-1" data-bottomsheet>The Bottomsheet</div>
The trigger should have an ID which would be used in the initialisation of the
bottomsheet, and a data attribute containing the ID referring to it's
corresponding bottomsheet data-bottomsheet-id=[id]
. The bottomsheet should
have the ID as well as the data attribute data-bottomsheet
JS:
BottomSheet({
trigger: 'trigger-1',
});
This would create a simple bottomsheet with the default props.
properties that are common for all layouts - bottomsheet, modal and sidesheet
The Id of the trigger element.
Type: string
Content needn't always be a DOM element, it could be passed in dynamically too, as a string.
Type: string
eg:
BottomSheet({
trigger: 'trigger-1',
content: `<div id="bottomsheet-1" data-bottomsheet>The Bottomsheet</div>`
});
The content that needs to remain fixed at the top of the sheet. It should have a class of 'header'.
Type: string
eg:
BottomSheet({
trigger: 'trigger-1',
headerContent: `<div class="header">...</div>`
});
The content that needs to remain fixed at the bottom of the sheet. It should have a class of 'footer'.
Type: string
eg:
BottomSheet({
trigger: 'trigger-1',
footerContent: `<div class="footer">...</div>`
});
A boolean defining whether to display an overlay or not.
Type: boolean
Default: false
This property determines the behavior of the sheet in web view, which can either be a modal or a sidesheet. Sidesheets can be configured to open from either the left or the right side of the screen.
Type: 'modal || sideSheetLeft || sideSheetRight'
Default: 'modal'
eg:
BottomSheet({
trigger: 'trigger-1',
content: <div id="bottomsheet-1" data-bottomsheet>The Bottomsheet</div>,
webLayout: 'sideSheetLeft'
});
This property enables the sheet to be automatically opened upon loading, without requiring a trigger. Since there is no trigger, the content needs to be dynamically passed in.
Type: boolean
Default: false
eg:
BottomSheet({
content: `<div id="maps-1" data-bottomsheet>The sheet</div>`,
openOnLoad: true,
});
This prop can be used to remove the sheet from the DOM on closing the sheet.
Type: boolean
Default: false
This property determines whether the sheet can be closed by the user or not. If set to false, the sheet cannot be translated below it's minimum snap point.
Type: boolean
Default: true
A boolean to keep the sheet open or close it by clicking on the overlay.
Type: boolean
Default: true
Defines whether the sheet is scrollable or not, when the sheet is at it's last snap point.
Type: booelean
Default: true
An array of all the snappoints you'd like the bottomsheet to snap at, from bottom to top. Works as percentage.
Note that mentioning 0 as the first snappoint will not open the sheet.
Type: Array of numbers(from 1 to 100)
Default: [100]
eg:
BottomSheet({
trigger: 'trigger-1',
snappoints: [20, 60, 100]
});
An area which would be sticky to the top of the sheet and would always listen to drag events, even if the content of the sheet is scrollable. It should have an ID.
Type: string
eg:
BottomSheet({
trigger: 'trigger-1',
content: <div id="bottomsheet-1" data-bottomsheet>The Bottomsheet</div>,
draggableArea: `<div id="drag"><svg width="45" height="7" viewBox="0 0 45 7" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="45" height="7" rx="3.5" fill="#38383D"/></svg></div>`,
});
The rubberband effect is only applicable if the sheet is at it's last snap point and is activated when scrollableSheet is set to false. It creates a snappy or bouncy behavior for the bottom sheet.
Type: booelean
Default: false
The velocity greater than which the bottomsheet would be translated to the next snappoint, otherwise it would snap back to the old one.
Type: number
Default: 0.9
The distance greater than which the bottomsheet would be translated to the next snappoint, otherwise it would snap back to the old one.
Type: number
Default: 150
It's an array of x and y positions in numbers as percentage for the modal.
Type: Array of numbers
Default: [50, 50]
Close icon for the modal in web.
Type: string
Default:
`<svg width="16" height="12" viewBox="0 0 39 38" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M33.112 36.9133C34.3649 38.15 36.3963 38.15 37.6492 36.9133C38.9022 35.6766 38.9022 33.6716 37.6492 32.435L24.0375 19L37.6492 5.56496C38.9022 4.3283 38.9022 2.32328 37.6492 1.08662C36.3963 -0.150042 34.3649 -0.150042 33.112 1.08662L19.5002 14.5216L5.88835 1.08655C4.63541 -0.150108 2.60401 -0.150107 1.35108 1.08655C0.0981471 2.32321 0.0981459 4.32824 1.35108 5.5649L14.9629 19L1.35108 32.435C0.0981434 33.6717 0.0981443 35.6767 1.35108 36.9134C2.60401 38.15 4.63541 38.15 5.88834 36.9134L19.5002 23.4783L33.112 36.9133Z" fill="white"/>
</svg>`
The minimum width at which you'd like a modal to appear.
Type: number
Default: 700
The minimum snap point percentage at which the sidesheet would open, resizing below it would close the sheet.
Type: number - 0 to 100
The maximum snap point percentage upto which the sidesheet can be resized.
Type: number - 0 to 100
This callback function can be used to perform operations during the initialization of the bottom sheet.
Type: function
eg:
BottomSheet({
trigger: `target-1`,
onInit: () => {
console.log("init");
}
});
This callback function can be used to perform operations once the sheet is open.
Type: function
eg:
BottomSheet({
trigger: `target-1`,
onOpen: () => {
console.log("open");
}
});
});
This callback function can be used to perform operations once the sheet is closed.
Type: function
eg:
BottomSheet({
trigger: `target-1`,
onClose: () => {
console.log("close");
}
});
This callback function allows you to perform operations when starting to drag the sheet.
Type: function
eg:
BottomSheet({
trigger: `target-1`,
onDragStart: () => {
console.log("drag start");
}
});
Operations to be run when dragging of the sheet ends can be done using this callback function.
Type: function
eg:
BottomSheet({
trigger: `target-1`,
onDragEnd: () => {
console.log("drag end");
}
});
Can be used to open the bottomsheet programatically. This works only if the sheet it already initialised.
eg:
let bottomsheet1 = BottomSheet({
trigger: `target-1`
}); //this would open the sheet by default
bottomsheet1.open() //can be used if it's necessary to open the sheet in any other scenario.
Can be used to close the bottomsheet programatically. This works only if the sheet it already initialised and open.
eg:
let bottomsheet1 = BottomSheet({
trigger: `target-1`
});
bottomsheet1.close()
"When no longer needed, the event listeners can be removed from the triggers using this method."
eg:
let bottomsheet1 = BottomSheet({
trigger: `target-1`
});
bottomsheet1.destroy()
The sheet can be re-initialised if needed, using this function.
eg:
let bottomsheet1 = BottomSheet({
trigger: `target-1`
});
bottomsheet1.init()
You can style the bottomsheet and other elements by overriding it's css styles.
Element | ClassName |
---|---|
Bottomsheet | 'bottomsheet' |
Overlay | 'overlay' |
Modal | 'modal' |
Modal Close Icon | 'close-modal' |
Draggable Area | 'draggable' |