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

@eduvidu/react-autoscale

v0.2.0

Published

A production-ready, enterprise-grade universal scaling engine for React. Zero config, SSR-safe, tree-shakeable.

Readme

@eduvidu/react-autoscale

A production-ready, enterprise-grade universal scaling engine for React.

Zero config • SSR-safe • Tree-shakeable • ~3KB gzipped

npm bundle size license


Features

  • 🪶 ~3KB gzipped — zero runtime dependencies
  • ResizeObserver + rAF batching — no layout thrashing
  • 🔒 SSR-safe — works with Next.js (App Router & Pages Router)
  • 🌳 Tree-shakeable — import only what you use
  • 🎯 Zero config — works with zero props out of the box
  • 📐 5 scale modeswidth, height, contain, cover, custom
  • 🪆 Nested scaling — context-aware deep nesting support
  • 🔌 Plugin-style — custom calculators, custom measurers
  • 📦 Dual ESM + CJS — with full TypeScript declarations

Installation

npm install @eduvidu/react-autoscale
# or
yarn add @eduvidu/react-autoscale
# or
pnpm add @eduvidu/react-autoscale

Peer dependencies: react >= 16.8.0


Compatibility

| React Version | Status | Notes | | ------------- | ------------ | ------------------------------------------ | | 16.8+ | ✅ Supported | Hooks baseline | | 17 | ✅ Tested | Full support | | 18 | ✅ Tested | StrictMode safe, concurrent rendering safe | | 19 | ✅ Tested | Full support |

StrictMode: The library is fully compatible with React 18+ StrictMode. In development mode, React double-invokes effects to catch bugs — useAutoScale correctly creates and tears down ResizeObserver and the rAF scheduler in each mount/unmount cycle with no duplicate observers or memory leaks.

Concurrent rendering: The library uses only stable React public APIs (useState, useRef, useCallback, useEffect, useMemo, useContext, forwardRef, useImperativeHandle, createContext). No internal or private React APIs are used. No assumptions that break under concurrent rendering.

SSR: All browser APIs (window, document, ResizeObserver, requestAnimationFrame) are guarded behind isBrowser() / isResizeObserverSupported() checks. The library renders safely in Next.js App Router, Pages Router, and any Node.js SSR environment — returning scale: 1 and isReady: false until the client hydrates.


Quick Start

Component API

import { AutoScale } from '@eduvidu/react-autoscale';

function Dashboard() {
  return (
    <div style={{ width: '100vw', height: '100vh' }}>
      <AutoScale>
        <div style={{ width: 1920, height: 1080 }}>
          {/* Your fixed-size content scales to fit */}
          <DashboardGrid />
        </div>
      </AutoScale>
    </div>
  );
}

Hook API

import { useAutoScale } from '@eduvidu/react-autoscale';

function ScalableTable() {
  const { containerRef, contentRef, scale, isReady } = useAutoScale({
    mode: 'width',
  });

  return (
    <div ref={containerRef} style={{ width: '100%', height: '100%' }}>
      <div
        ref={contentRef}
        style={{
          transform: `scale(${scale})`,
          transformOrigin: 'top left',
          opacity: isReady ? 1 : 0,
        }}
      >
        <LargeTable />
      </div>
    </div>
  );
}

API Reference

<AutoScale>

Declarative scaling wrapper. All props optional.

| Prop | Type | Default | Description | | --------------------- | --------------------------------------------- | -------------- | ------------------------------------------- | | mode | 'width' \| 'height' \| 'contain' \| 'cover' | 'contain' | Scale strategy | | minScale | number | — | Minimum scale factor | | maxScale | number | — | Maximum scale factor | | customCalculator | (container, content) => number | — | Custom scale function (overrides mode) | | observeParent | boolean | false | Observe parent element instead of container | | transformOrigin | string | 'top left' | CSS transform-origin | | throttle | number | — | Min interval (ms) between recalculations | | debounce | number | — | Debounce delay (ms) | | disabled | boolean | false | Disable scaling entirely | | debug | boolean | false | Log measurements to console | | compensationMode | 'none' \| 'width' \| 'height' \| 'both' | 'none' | Adjust container size after scaling | | onScaleChange | (scale, details) => void | — | Called when scale changes | | measurementStrategy | 'scrollSize' \| 'boundingRect' \| 'custom' | 'scrollSize' | How to measure content size | | customMeasurer | (element) => { width, height } | — | Custom measurement function | | contentClassName | string | — | Class for inner content wrapper | | contentStyle | CSSProperties | — | Style for inner content wrapper |

All standard <div> attributes (className, id, data-*, onClick, etc.) are forwarded to the outer container.

useAutoScale(options?)

Returns:

| Property | Type | Description | | --------------------- | --------------------------- | ------------------------------------- | | containerRef | RefObject<HTMLDivElement> | Attach to container element | | contentRef | RefObject<HTMLDivElement> | Attach to content element | | scale | number | Current scale factor (default 1) | | dimensions | { width, height } | Scaled content dimensions | | containerDimensions | { width, height } | Container dimensions | | contentDimensions | { width, height } | Natural (unscaled) content dimensions | | isReady | boolean | true after first measurement |

ScaleProvider / useScaleContext()

For nested scaling awareness:

import { useScaleContext } from '@eduvidu/react-autoscale';

function NestedWidget() {
  const { scale, parentScale, depth } = useScaleContext();
  // scale = this level's scale
  // parentScale = accumulated scale from all ancestors
  // depth = nesting level (0 = no AutoScale ancestor)
}

Core Utilities

These are framework-agnostic and can be used independently:

import {
  calculateScale,
  clampScale,
  measureElement,
  measureContainer,
  createScheduler,
  isBrowser,
  canUseDom,
} from '@eduvidu/react-autoscale';

Examples

Nested Scaling

<AutoScale mode="contain">
  <div style={{ width: 1920, height: 1080 }}>
    <Header />
    <AutoScale mode="width">
      <DataTable columns={50} />
    </AutoScale>
    <Footer />
  </div>
</AutoScale>

Custom Scale Calculator

<AutoScale
  customCalculator={(container, content) => {
    // Scale to 80% of container width
    return (container.width * 0.8) / content.width;
  }}
>
  <WidgetPanel />
</AutoScale>

Scale Change Tracking

<AutoScale
  onScaleChange={(scale, { previousScale, containerDimensions }) => {
    analytics.track('scale_changed', { scale, previousScale });
  }}
>
  <Dashboard />
</AutoScale>

Compensation Mode

When you need surrounding content to flow around the scaled content:

<AutoScale compensationMode="height" mode="width">
  {/* Container height adjusts to match scaled content height */}
  <FixedWidthContent />
</AutoScale>

With Clamping

<AutoScale minScale={0.5} maxScale={2}>
  <ResponsivePanel />
</AutoScale>

Debounced Scaling

<AutoScale debounce={150}>
  <ExpensiveChart />
</AutoScale>

Next.js Usage

Works out of the box with both App Router and Pages Router:

// app/dashboard/page.tsx (App Router)
'use client';

import { AutoScale } from '@eduvidu/react-autoscale';

export default function DashboardPage() {
  return (
    <div style={{ width: '100vw', height: '100vh' }}>
      <AutoScale>
        <div style={{ width: 1920, height: 1080 }}>
          <DashboardContent />
        </div>
      </AutoScale>
    </div>
  );
}

Note: Since AutoScale uses useRef and useEffect, it must be a client component. Add 'use client' at the top of the file when using App Router.


Vite Usage

// src/App.tsx
import { AutoScale } from '@eduvidu/react-autoscale';

function App() {
  return (
    <AutoScale style={{ width: '100vw', height: '100vh' }}>
      <div style={{ width: 1440, height: 900 }}>
        <MyApp />
      </div>
    </AutoScale>
  );
}

Performance Notes

How it works

  1. ResizeObserver watches the container for size changes
  2. rAF batching coalesces rapid resize events into a single frame
  3. Epsilon comparison (1e-4) skips React re-renders when scale hasn't meaningfully changed
  4. Stable refs prevent unnecessary observer re-creation
  5. transform: scale() is GPU-accelerated — no reflow triggered

What we avoid

  • zoom property (inconsistent cross-browser)
  • ❌ Measuring scaled dimensions (leads to feedback loops)
  • ❌ Layout thrashing (no interleaved reads/writes)
  • ❌ ResizeObserver loop errors (rAF wrapping)
  • ❌ Memory leaks (observer disconnect + scheduler destroy on unmount)

Anti-Patterns

// ❌ BAD: Don't set explicit width/height on the AutoScale container
// (it needs to fill available space to calculate scale)
<AutoScale style={{ width: 500, height: 300 }}>...</AutoScale>

// ✅ GOOD: Let it fill its parent
<div style={{ width: 500, height: 300 }}>
  <AutoScale>...</AutoScale>
</div>
// ❌ BAD: Don't apply transform to children manually
<AutoScale>
  <div style={{ transform: 'scale(2)' }}>...</div>
</AutoScale>

// ✅ GOOD: Let AutoScale handle all transforms
<AutoScale>
  <div>...</div>
</AutoScale>

Competitor Comparison

| Feature | @eduvidu/react-autoscale | react-fit | react-zoom-pan-pinch | | ------------------ | ----------------------------------------- | --------- | -------------------- | | Bundle (gzip) | ~3KB | ~8KB | ~45KB | | Dependencies | 0 | Multiple | Multiple | | Scale modes | 5 (width/height/contain/cover/custom) | 1 | Pan/zoom only | | SSR safe | | ❌ | ❌ | | Tree-shakeable | | ❌ | ❌ | | rAF batching | | ❌ | Partial | | Nested scaling | | ❌ | ❌ | | Zero config | | ❌ | ❌ | | Plugin calculators | | ❌ | ❌ | | Compensation modes | | ❌ | ❌ |


Known Limitations

  1. Content must have intrinsic size — the content children should have explicit or natural dimensions for measurement to work. Flexbox/grid children that stretch may report incorrect sizes.

  2. CSS transitions on scaled content — adding transition: transform to the content div may cause visual jitter during rapid resizing.

  3. Hidden containers — if the container is display: none at mount time, the initial measurement will be 0. Scale will recalculate when the container becomes visible.

  4. iframe content — content inside iframes cannot be measured by the parent's ResizeObserver.


Publishing

# 1. Build
npm run build

# 2. Test
npm test

# 3. Type-check
npm run typecheck

# 4. Dry run
npm pack --dry-run

# 5. Publish
npm publish --access public

Development

# Install
npm install

# Dev mode (watch)
npm run dev

# Test (watch)
npm run test:watch

# Test with coverage
npm run test:coverage

# Lint
npm run lint

# Format
npm run format

# Build
npm run build

Future Roadmap

  • [ ] useAutoScaleTransition — animated scale transitions
  • [ ] direction: 'rtl' support for transform-origin
  • [ ] Resize breakpoint callbacks
  • [ ] Performance observer integration
  • [ ] React Native support (experimental)
  • [ ] Storybook examples
  • [ ] Playground website

License

MIT © eduvidu