๐ A lightweight, performant, and accessible action sheet component for React with modern features and best practices.
- ๐ High Performance: 60fps animations with optimized rendering
- โฟ Accessible: WCAG compliant with keyboard navigation and screen reader support
- ๐ฑ Touch Friendly: Responsive gestures for mobile devices
- ๐จ Customizable: Full control over styling and behavior
- ๐ง TypeScript: Full TypeScript support with comprehensive type definitions
- ๐ฆ Lightweight: Minimal bundle size with zero dependencies
- โก Modern React: Built with React 18+ features and hooks
- ๐ฏ Position Flexible: Support for bottom and top positioned sheets
actionsheet-demo.mp4
# Using npm
npm install actionsheet-react
# Using yarn
yarn add actionsheet-react
# Using pnpm
pnpm add actionsheet-react
import React, { useRef } from "react";
import ActionSheet from "actionsheet-react";
function MyComponent() {
const actionSheetRef = useRef<ActionSheetRef>(null);
return (
<div>
<button onClick={() => actionSheetRef.current?.open()}>
Open Action Sheet
</button>
<ActionSheet
ref={actionSheetRef}
onClose={() => console.log("Closed!")}
aria-label="Example action sheet"
>
<div style={{ padding: "20px" }}>
<h3>Hello World!</h3>
<p>This is a basic action sheet.</p>
<button onClick={() => actionSheetRef.current?.close()}>Close</button>
</div>
</ActionSheet>
</div>
);
}
Prop | Type | Default | Description |
---|---|---|---|
onClose |
() => void |
undefined |
Callback fired when the action sheet is closed |
children |
ReactNode |
undefined |
Content to render inside the action sheet |
bgStyle |
CSSProperties |
{} |
Custom styles for the background overlay |
sheetStyle |
CSSProperties |
{} |
Custom styles for the sheet container |
mouseEnable |
boolean |
true |
Enable mouse/pointer interactions for dragging |
touchEnable |
boolean |
true |
Enable touch interactions for dragging |
threshold |
number |
50 |
Threshold in pixels for triggering close when dragging |
opacity |
number |
1 |
Opacity of the background overlay when visible |
zIndex |
number |
998 |
z-index value for the action sheet |
closeOnBgTap |
boolean |
true |
Allow closing when clicking on the background |
bgTransition |
string |
"opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1)" |
CSS transition for background |
className |
string |
"action-sheet" |
CSS class name for the background overlay |
sheetTransition |
string |
"transform 0.3s cubic-bezier(0.4, 0, 0.2, 1)" |
CSS transition for sheet |
reverse |
boolean |
false |
Position the sheet at the top instead of bottom |
aria-label |
string |
undefined |
ARIA label for accessibility |
aria-labelledby |
string |
undefined |
ARIA labelledby for accessibility |
Method | Description |
---|---|
open() |
Open the action sheet |
close() |
Close the action sheet |
isOpen() |
Check if the action sheet is currently open |
import React, { useRef } from "react";
import ActionSheet, { ActionSheetRef } from "actionsheet-react";
function BasicExample() {
const actionSheetRef = useRef<ActionSheetRef>(null);
return (
<>
<button onClick={() => actionSheetRef.current?.open()}>
Open Basic Sheet
</button>
<ActionSheet ref={actionSheetRef}>
<div style={{ padding: "20px" }}>
<h3>Basic Action Sheet</h3>
<p>Drag down, click background, or press Escape to close.</p>
</div>
</ActionSheet>
</>
);
}
function TopSheetExample() {
const actionSheetRef = useRef<ActionSheetRef>(null);
return (
<>
<button onClick={() => actionSheetRef.current?.open()}>
Open Top Sheet
</button>
<ActionSheet
ref={actionSheetRef}
reverse={true}
aria-label="Top positioned action sheet"
>
<div style={{ padding: "20px" }}>
<h3>Top Action Sheet</h3>
<p>This sheet slides down from the top!</p>
</div>
</ActionSheet>
</>
);
}
function CustomStyledExample() {
const actionSheetRef = useRef<ActionSheetRef>(null);
return (
<>
<button onClick={() => actionSheetRef.current?.open()}>
Open Custom Sheet
</button>
<ActionSheet
ref={actionSheetRef}
bgStyle={{ backgroundColor: "rgba(139, 69, 19, 0.8)" }}
sheetStyle={{
backgroundColor: "#1a1a1a",
color: "#ffffff",
borderRadius: "20px 20px 0 0",
}}
aria-label="Custom styled action sheet"
>
<div style={{ padding: "20px" }}>
<h3>Custom Styled Sheet</h3>
<p>This sheet has custom background and styling.</p>
</div>
</ActionSheet>
</>
);
}
function ActionListExample() {
const actionSheetRef = useRef<ActionSheetRef>(null);
const [selectedAction, setSelectedAction] = useState("");
const handleAction = (action: string) => {
setSelectedAction(action);
actionSheetRef.current?.close();
};
return (
<>
<button onClick={() => actionSheetRef.current?.open()}>
Open Action List
</button>
<ActionSheet ref={actionSheetRef} threshold={80}>
<div>
<div style={{ padding: "20px", borderBottom: "1px solid #eee" }}>
<h3>Choose an Action</h3>
</div>
<div>
{["Share", "Edit", "Copy Link", "Download", "Delete"].map(
action => (
<button
key={action}
onClick={() => handleAction(action)}
style={{
width: "100%",
padding: "15px 20px",
border: "none",
background: "white",
borderBottom: "1px solid #f0f0f0",
textAlign: "left",
cursor: "pointer",
}}
>
{action}
</button>
)
)}
</div>
</div>
</ActionSheet>
{selectedAction && <p>Selected: {selectedAction}</p>}
</>
);
}
ActionSheet-React is built with accessibility in mind:
- ARIA Support: Proper ARIA attributes for screen readers
- Keyboard Navigation: Press
Escape
to close the sheet - Focus Management: Automatic focus handling when opening/closing
- Screen Reader Support: Compatible with popular screen readers
<ActionSheet
ref={actionSheetRef}
aria-label="User settings"
// or
aria-labelledby="settings-title"
>
<div>
<h3 id="settings-title">User Settings</h3>
{/* Content */}
</div>
</ActionSheet>
You can use CSS custom properties for consistent theming:
:root {
--actionsheet-bg-color: rgba(0, 0, 0, 0.5);
--actionsheet-sheet-bg: #ffffff;
--actionsheet-border-radius: 16px;
--actionsheet-transition: 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.action-sheet {
background-color: var(--actionsheet-bg-color);
}
<ActionSheet
bgTransition="opacity 0.5s ease-in-out"
sheetTransition="transform 0.5s cubic-bezier(0.34, 1.56, 0.64, 1)"
>
{/* Content */}
</ActionSheet>
- Memoize Content: Use
React.memo
for complex sheet content - Optimize Images: Use appropriate image formats and sizes
- Avoid Heavy Computations: Keep sheet content lightweight
- Use CSS Transforms: Prefer CSS transforms over changing layout properties
const OptimizedSheetContent = memo(({ data }) => (
<div>{/* Heavy content here */}</div>
));
<ActionSheet ref={ref}>
<OptimizedSheetContent data={data} />
</ActionSheet>;
- React Version: Now requires React 16.8+
- TypeScript: Better type definitions
- Props: Some prop names have changed for clarity
- Accessibility: New ARIA props added
// v1.x
<ActionSheet
ref={ref}
onClose={handleClose}
bgTransition="opacity 0.5s ease-in-out, z-index 0.5s ease-in-out"
/>
// v2.x
<ActionSheet
ref={ref}
onClose={handleClose}
bgTransition="opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1)"
aria-label="Action sheet"
/>
Contributions are welcome! Please read our Contributing Guide for details.
ISC ยฉ mohit23x
Built with โค๏ธ by mohit23x
### ๐จโ๐ป Usage
##### Sample code using Javascript
```javascript
import React, { useRef, Fragment } from "react";
import ActionSheet from "actionsheet-react";
const MyComponent = () => {
const ref = useRef();
const handleOpen = () => {
ref.current.open();
};
const handleClose = () => {
ref.current.close();
};
return (
<Fragment>
<button onClick={handleOpen}>Open</button>
<button onClick={handleClose}>Close</button>
<ActionSheet ref={ref}>
<div style={style.content}>๐ Hi React Devs!</div>
</ActionSheet>
</Fragment>
);
};
const style = {
content: {
height: 300,
display: "flex",
justifyContent: "center",
alignItems: "center",
},
};
import ActionSheet, {ActionSheetRef} from 'actionsheet-react';
const MyComponent = () => {
const ref = useRef<ActionSheetRef>();
// ...rest same as above code
property name | type | more info |
---|---|---|
onClose | callback function | called when the actionsheet is closed |
children | React Children | all the fancy HTML elements that you want to show in the menu |
bgStyle | css styles object | these styles are applied to the background black overlay |
sheetStyle | css styles object | these styles are applied to the sheet component |
mouseEnable | boolean | if true, the sheet can be dragged down using mouse |
touchEnable | boolean | if true, the sheet can be swiped down on touch devices |
threshold | number | the minimum distance dragged, so that sheet will slide down. Threshold is measured in px , default value is 50 |
zIndex | number | the default value is 999 |
closeOnBgTap | boolean | if true, the sheet is closed when the background overlay is tapped |
reverse | boolean | open the sheet in reverse direction |
sheetTransition | string | css transition shorthand, default value transform 0.3s ease-in-out |
bgTransition | string | css transition shorthand, default value opacity 0.5s ease-in-out, z-index 0.5s ease-in-out |
- The logic to stop the backgroud from scrolling is not implemented in this package just to keep it simple. To avoid the background from scrolling you can toggle the overflow property of the body tag, or you can also use some other way of your choice
document.body.style.overflow = "hidden";
document.body.style.overflow = "auto";
- Mobile browsers generally have pull-to-refresh and when action sheet is open and when user drags the sheet down the pull-to-refresh is triggered. To control this behavior either you can disable swipe in action sheet
touchEnable={false}
or you can disable pull-to-refresh.
body {
overscroll-behavior: contain;
}
The github repo is always there for you.