Skip to content

mohit23x/actionsheet-react

Repository files navigation

ActionSheet-React

Size npm TypeScript License

๐ŸŒŸ A lightweight, performant, and accessible action sheet component for React with modern features and best practices.

โœจ Features

  • ๐Ÿš€ 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

๐Ÿ“บ Demo

CodeSandbox

actionsheet-demo.mp4

๐Ÿ“ฆ Installation

# Using npm
npm install actionsheet-react

# Using yarn
yarn add actionsheet-react

# Using pnpm
pnpm add actionsheet-react

๐Ÿš€ Quick Start

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>
  );
}

๐Ÿ“– API Reference

Props

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

Ref Methods

Method Description
open() Open the action sheet
close() Close the action sheet
isOpen() Check if the action sheet is currently open

๐ŸŽฏ Usage Examples

Basic Usage

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>
    </>
  );
}

Top Position Sheet

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>
    </>
  );
}

Custom Styled Sheet

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>
    </>
  );
}

Action List Example

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>}
    </>
  );
}

โ™ฟ Accessibility

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

Accessibility Best Practices

<ActionSheet
  ref={actionSheetRef}
  aria-label="User settings"
  // or
  aria-labelledby="settings-title"
>
  <div>
    <h3 id="settings-title">User Settings</h3>
    {/* Content */}
  </div>
</ActionSheet>

๐ŸŽจ Styling

CSS Custom Properties

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);
}

Custom Animations

<ActionSheet
  bgTransition="opacity 0.5s ease-in-out"
  sheetTransition="transform 0.5s cubic-bezier(0.34, 1.56, 0.64, 1)"
>
  {/* Content */}
</ActionSheet>

๐Ÿš€ Performance Tips

  1. Memoize Content: Use React.memo for complex sheet content
  2. Optimize Images: Use appropriate image formats and sizes
  3. Avoid Heavy Computations: Keep sheet content lightweight
  4. 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>;

๐Ÿ”„ Migration from v1.x

Breaking Changes

  1. React Version: Now requires React 16.8+
  2. TypeScript: Better type definitions
  3. Props: Some prop names have changed for clarity
  4. Accessibility: New ARIA props added

Migration Guide

// 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"
/>

๐Ÿค Contributing

Contributions are welcome! Please read our Contributing Guide for details.

๐Ÿ“„ License

ISC ยฉ mohit23x

๐Ÿ™ Credits

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",
  },
};
Sample code using Typescript
import ActionSheet, {ActionSheetRef} from 'actionsheet-react';

const MyComponent = () => {
  const ref = useRef<ActionSheetRef>();

  // ...rest same as above code

๐ŸŒฎ Props

all props are optional
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

๐Ÿ‘พ Misc

  1. 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";
  1. 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;
}

โ›ณ Issues/Feature Request/Pull Request

The github repo is always there for you.

About

React action sheet component

Topics

Resources

Stars

Watchers

Forks

Packages

No packages published

Contributors 7