npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@capgo/capacitor-sheets

v8.0.11

Published

Framework-agnostic swipeable sheets, drawers, dialogs, and scroll primitives for Capacitor apps

Readme

@capgo/capacitor-sheets

Framework-agnostic sheets, drawers, dialogs, scroll helpers, and overlay primitives for Capacitor apps.

This package is inspired by the public Silk feature surface, but it is not a wrapper around Silk and does not include Silk source code. It uses platform web APIs and custom elements so the same primitives work in React, Vue, Angular, Svelte, Solid, or plain TypeScript.

Usecase Demos

Each usecase has its own animated WebP demo. These match the public Silk-style example set: long sheets, detents, sidebars, bottom/top sheets, keyboard-aware sheets, toasts, detached sheets, full pages, stacking, depth, parallax, lightboxes, persistent detents, and cards.

Online Playgrounds

Each framework example opens the same 16-usecase gallery, so StackBlitz is useful for testing the full surface instead of a single smoke-test sheet:

Mobile Test App

The repo includes a Capacitor app that wraps the React gallery so the sheets can be tested on real iOS and Android devices. The app id is app.capgo.capacitor.sheets. Capacitor 8 requires Node.js 22 or newer for local mobile commands.

npm run build:mobile
npx cap run ios
npx cap run android

Capgo OTA uploads use the same built gallery:

npx @capgo/cli@latest app add app.capgo.capacitor.sheets --name "Capgo Sheets"
npm run deploy:capgo:dev
npm run deploy:capgo

Create the Capgo app once before the first upload. GitHub Actions also include a Capgo deploy workflow. Tag builds deploy to production, alpha tags deploy to dev, and manual runs can choose either channel. Set CAPGO_TOKEN in repository secrets before running it.

Features

  • Framework agnostic custom elements: no React runtime dependency in the core package.
  • Bottom sheets, side drawers, top sheets, and centered dialogs through content-placement.
  • Detents with em, rem, dvh, lvh, svh, calc(), and other modern CSS lengths.
  • Touch, pointer, wheel, and trackpad gestures with dismissal, overshoot, and trap controls.
  • Modal behavior: focus trap, focus restore, Escape dismissal, outside-click dismissal, and inert outside content.
  • Capacitor safe-area defaults using env(safe-area-inset-*) plus Capacitor SystemBars --safe-area-inset-* fallbacks.
  • Keyboard-aware layout using visualViewport resize/scroll events and preventScroll focus behavior.
  • Overlay compatibility through cap-island and cap-external-overlay.
  • Stacking and outlet animation hooks for depth effects and coordinated page motion.
  • Scroll primitives with progress/distance helpers.
  • Theme color dimming for Capacitor WebViews and mobile browsers.
  • Modern CSS defaults authored with em-based sizing, with no design-system lock-in.

Usecase Coverage

| Usecase | Capgo Sheets pattern | | ---------------------------- | --------------------------------------------------------------------------------------------------------- | | Long Sheet | cap-sheet + cap-scroll or naturally scrolling cap-sheet-content | | Sheet with Detent | detents="18em 32em" and stepTo() / cap-sheet-trigger action="step" | | Sidebar | content-placement="left" or content-placement="right" | | Bottom Sheet | default content-placement="bottom" | | Sheet with Keyboard | visual viewport offset support via native-focus-scroll-prevention | | Toast | inert-outside="false", close-on-outside-click="false", focus-trap="false" | | Detached Sheet | rounded content with margins and cap-sheet-special-wrapper composition | | Page from Bottom | full-height bottom sheet content | | Top Sheet | content-placement="top" | | Sheet with Stacking | cap-sheet-stack, stack depth variables, and stacking animation hooks | | Sheet with Depth | cap-sheet-outlet progress variables and travelAnimation | | Parallax Page | cap-sheet-outlet + cap-scroll progress composition | | Page | full-viewport sheet content or side-entering content-placement | | Lightbox | content-placement="center" plus backdrop and media content | | Persistent Sheet with Detent | default-presented, swipe-dismissal="false", inert-outside="false", close-on-outside-click="false" | | Card | content-placement="center" with compact content |

Installation

npm install @capgo/capacitor-sheets
npx cap sync

Capacitor Setup

Add viewport-fit=cover so iOS exposes safe-area insets to CSS:

<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />

Safe areas are enabled by default. cap-sheet-view reads standard env(safe-area-inset-*) values and Capacitor SystemBars fallback variables such as --safe-area-inset-bottom, then applies them to the sheet viewport in em-based layout. You can opt out or choose edges per sheet:

<cap-sheet safe-area="none"></cap-sheet>
<cap-sheet safe-area="bottom left right"></cap-sheet>

For Capacitor apps with overlay status/system bars, keep the platform plugins responsible for exposing correct insets:

import type { CapacitorConfig } from '@capacitor/cli';

const config: CapacitorConfig = {
  plugins: {
    StatusBar: {
      overlaysWebView: true,
    },
    Keyboard: {
      resize: 'body',
      resizeOnFullScreen: true,
    },
    SystemBars: {
      insetsHandling: 'css',
    },
  },
};

export default config;

Keyboard handling is on by default through native-focus-scroll-prevention. It listens to visualViewport changes, keeps focused controls visible above the keyboard, and restores the sheet offset when the keyboard closes.

Vanilla Usage

<script type="module">
  import '@capgo/capacitor-sheets';
</script>

<cap-sheet-trigger for="booking-sheet" action="present">Open</cap-sheet-trigger>

<cap-sheet id="booking-sheet" detents="18em 32em" content-placement="bottom">
  <cap-sheet-portal>
    <cap-sheet-view>
      <cap-sheet-backdrop></cap-sheet-backdrop>
      <cap-sheet-content class="sheet">
        <cap-sheet-bleeding-background></cap-sheet-bleeding-background>
        <cap-sheet-handle></cap-sheet-handle>
        <cap-sheet-title>Evening route</cap-sheet-title>
        <cap-sheet-description>Choose a route and confirm pickup.</cap-sheet-description>
        <cap-sheet-trigger action="dismiss">Done</cap-sheet-trigger>
      </cap-sheet-content>
    </cap-sheet-view>
  </cap-sheet-portal>
</cap-sheet>
.sheet {
  width: min(100%, 34em);
  padding: 0 1.25em 1.25em;
}

Five Framework Examples

Full runnable examples live in:

  • examples/react-app
  • examples/vue-app
  • examples/angular-app
  • examples/svelte-app
  • examples/solid-app

All five apps mount the shared usecase gallery from examples/shared/usecase-gallery.ts. That gallery covers Long Sheet, Sheet with Detent, Sidebar, Bottom Sheet, Sheet with Keyboard, Toast, Detached Sheet, Page from Bottom, Top Sheet, Sheet with Stacking, Sheet with Depth, Parallax Page, Page, Lightbox, Persistent Sheet with Detent, and Card.

React

import { setupSheet } from '@capgo/capacitor-sheets/react';
import { useEffect, useRef } from 'react';
import '@capgo/capacitor-sheets';
import { mountUsecaseGallery } from '../../shared/usecase-gallery';

export function App() {
  const galleryRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    if (!galleryRef.current) return;
    return mountUsecaseGallery(galleryRef.current, {
      framework: 'React',
      setupSheet,
    });
  }, []);

  return <div ref={galleryRef} />;
}

Vue

<script setup lang="ts">
import { onMounted, onUnmounted, ref } from 'vue';
import { setupSheet } from '@capgo/capacitor-sheets/vue';
import '@capgo/capacitor-sheets';
import { mountUsecaseGallery } from '../../shared/usecase-gallery';

const galleryRef = ref<HTMLElement | null>(null);
let cleanup: (() => void) | undefined;

onMounted(() => {
  if (galleryRef.value) {
    cleanup = mountUsecaseGallery(galleryRef.value, {
      framework: 'Vue',
      setupSheet,
    });
  }
});

onUnmounted(() => cleanup?.());
</script>

<template>
  <div ref="galleryRef"></div>
</template>

Angular

import type { AfterViewInit, ElementRef, OnDestroy } from '@angular/core';
import { Component, CUSTOM_ELEMENTS_SCHEMA, ViewChild } from '@angular/core';
import { setupSheet } from '@capgo/capacitor-sheets/angular';
import '@capgo/capacitor-sheets';
import { mountUsecaseGallery } from '../../../shared/usecase-gallery';

@Component({
  selector: 'app-root',
  standalone: true,
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
  template: `<div #gallery></div>`,
})
export class AppComponent implements AfterViewInit, OnDestroy {
  @ViewChild('gallery', { static: true }) gallery?: ElementRef<HTMLElement>;
  private cleanup?: () => void;

  ngAfterViewInit(): void {
    if (this.gallery?.nativeElement) {
      this.cleanup = mountUsecaseGallery(this.gallery.nativeElement, {
        framework: 'Angular',
        setupSheet,
      });
    }
  }

  ngOnDestroy(): void {
    this.cleanup?.();
  }
}

Svelte

<script lang="ts">
  import { onMount } from 'svelte'
  import { setupSheet } from '@capgo/capacitor-sheets/svelte'
  import '@capgo/capacitor-sheets'
  import { mountUsecaseGallery } from '../../shared/usecase-gallery'

  let gallery: HTMLDivElement

  onMount(() =>
    mountUsecaseGallery(gallery, {
      framework: 'Svelte',
      setupSheet,
    }),
  )
</script>

<div bind:this={gallery}></div>

Solid

import { onCleanup, onMount } from 'solid-js';
import { setupSheet } from '@capgo/capacitor-sheets/solid';
import '@capgo/capacitor-sheets';
import { mountUsecaseGallery } from '../../shared/usecase-gallery';

export function App() {
  let galleryEl!: HTMLDivElement;

  onMount(() => {
    const cleanup = mountUsecaseGallery(galleryEl, {
      framework: 'Solid',
      setupSheet,
    });
    onCleanup(cleanup);
  });

  return <div ref={galleryEl} />;
}

API Surface

Core elements:

  • cap-sheet: state, detents, placement, gestures, modal behavior, lifecycle events.
  • cap-sheet-trigger: declarative present, dismiss, toggle, and step actions.
  • cap-sheet-portal: optional body portal for overlay layering.
  • cap-sheet-view: viewport overlay host.
  • cap-sheet-backdrop: progress-synced modal backdrop.
  • cap-sheet-content: accessible sheet surface.
  • cap-sheet-bleeding-background: background extension for rounded edge sheets.
  • cap-sheet-handle: draggable and keyboard-accessible detent handle.
  • cap-sheet-title and cap-sheet-description: accessible naming.
  • cap-sheet-special-wrapper and cap-sheet-special-wrapper-content: composition hooks for detached sheets, cards, lightboxes, and custom page layouts.
  • cap-sheet-stack: groups sheets for stacked depth.
  • cap-sheet-outlet: receives sheet progress variables and optional travelAnimation.
  • cap-scroll and cap-scroll-content: scroll progress helpers.
  • cap-fixed, cap-island, cap-external-overlay, cap-visually-hidden, cap-auto-focus-target: composition and accessibility helpers.

Important events:

  • cap-sheet-presented-change
  • cap-sheet-active-detent-change
  • cap-sheet-travel
  • cap-sheet-travel-status-change
  • cap-sheet-travel-range-change
  • cap-sheet-drag-start
  • cap-sheet-drag-end
  • cap-scroll

Imperative methods on cap-sheet:

const sheet = document.querySelector('cap-sheet')!;
await sheet.present();
await sheet.dismiss();
await sheet.toggle();
await sheet.stepTo(2);
await sheet.step('down');

The public TypeScript API is documented with TSDoc in src/core/types.ts, and generated declarations are emitted during npm run build.

Development

npm install
npm run render:demos
npm run build
npm run dev:examples -- react vue svelte angular solid

In the Capgo monorepo, use bun and bunx for local commands.