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

hq-cropper

v4.0.0

Published

Image cropper tool

Readme

hq-cropper

npm version Downloads License: MIT

A lightweight, zero-dependency image cropper for high-quality square crops. Perfect for profile pictures, avatars, and thumbnails.

Documentation | Live Demo

Features

  • Zero dependencies — pure TypeScript
  • Mobile-friendly with full touch support
  • High-quality output with configurable compression
  • Square crop with resizable portal
  • Drag and resize from all corners
  • File validation (type and size)
  • Error handling with callbacks
  • Fully customizable styling
  • Inherits fonts from your application
  • Works with any framework (React, Vue, Angular, vanilla JS)

Installation

npm install hq-cropper
pnpm add hq-cropper
yarn add hq-cropper

Quick Start

import { HqCropper } from 'hq-cropper'

const cropper = HqCropper((base64, blob, state) => {
    console.log('Cropped image:', base64)
    console.log('Blob:', blob)
    console.log('Original file:', state.fileName)
})

// Open file picker
document.querySelector('#crop-button').addEventListener('click', () => {
    cropper.open()
})

API

HqCropper(onSubmit, config?, css?, onError?)

Creates a new cropper instance.

const cropper = HqCropper(
    onSubmit, // Required: callback with result
    config, // Optional: configuration options
    css, // Optional: custom CSS class names
    onError // Optional: error handler
)

Parameters

| Parameter | Type | Description | | ---------- | ----------------------------------------------------------------------- | ----------------------------------------- | | onSubmit | (base64: string, blob: Blob \| null, state: ApplicationState) => void | Called when user applies the crop | | config | Partial<ConfigurationOptions> | Configuration options | | css | Partial<ClassNames> | Custom CSS class names | | onError | (message: string) => void | Called on validation or processing errors |

Returns

interface HqCropperInstance {
    open: () => void // Opens file picker dialog
}

Configuration

| Option | Type | Default | Description | | ------------------- | ------------------------------ | -------------------------------------------------------- | -------------------------------------------------- | | portalSize | number | 150 | Initial size of crop portal in pixels | | minPortalSize | number | 50 | Minimum portal size (prevents too small crops) | | portalPosition | [number, number] \| 'center' | 'center' | Initial portal position | | framePadding | number | 3 | Padding around the image frame | | outputSize | number | 0 | Output size in pixels (0 = use original selection) | | compression | number | 1 | JPEG compression (0-1, where 1 is best quality) | | type | 'jpeg' \| 'png' | 'jpeg' | Output image format | | maxFileSize | number | 0 | Max input file size in bytes (0 = no limit) | | allowedTypes | string[] | ['image/jpeg', 'image/png', 'image/gif', 'image/webp'] | Allowed MIME types | | applyButtonLabel | string | 'Apply' | Apply button text | | cancelButtonLabel | string | 'Cancel' | Cancel button text |

Configuration Examples

Fixed Output Size (512x512 PNG)

const cropper = HqCropper(onSubmit, {
    type: 'png',
    outputSize: 512,
    compression: 1,
})

Compressed JPEG for Smaller Files

const cropper = HqCropper(onSubmit, {
    type: 'jpeg',
    outputSize: 256,
    compression: 0.7,
})

File Size Restriction

const cropper = HqCropper(
    onSubmit,
    {
        maxFileSize: 5 * 1024 * 1024, // 5MB
        allowedTypes: ['image/jpeg', 'image/png'],
    },
    undefined,
    (error) => alert(error)
)

Custom Button Labels

const cropper = HqCropper(onSubmit, {
    applyButtonLabel: 'Сохранить',
    cancelButtonLabel: 'Отмена',
})

Framework Examples

React

import { useRef, useState } from 'react'
import { HqCropper } from 'hq-cropper'

function AvatarUpload() {
    const [avatar, setAvatar] = useState<string>('')

    const cropperRef = useRef(
        HqCropper(
            (base64) => setAvatar(base64),
            { portalSize: 200 },
            undefined,
            (error) => console.error(error)
        )
    )

    return (
        <div>
            {avatar && <img src={avatar} alt="Avatar" />}
            <button onClick={() => cropperRef.current.open()}>
                Upload Avatar
            </button>
        </div>
    )
}

Vue 3

<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { HqCropper, type HqCropperInstance } from 'hq-cropper'

const avatar = ref('')
let cropper: HqCropperInstance

onMounted(() => {
    cropper = HqCropper((base64) => {
        avatar.value = base64
    })
})

const openCropper = () => cropper.open()
</script>

<template>
    <div>
        <img v-if="avatar" :src="avatar" alt="Avatar" />
        <button @click="openCropper">Upload Avatar</button>
    </div>
</template>

Vanilla JavaScript

<img id="preview" src="" alt="Preview" style="display: none;" />
<button id="upload-btn">Upload Image</button>

<script type="module">
    import { HqCropper } from 'hq-cropper'

    const preview = document.getElementById('preview')
    const button = document.getElementById('upload-btn')

    const cropper = HqCropper((base64, blob, state) => {
        preview.src = base64
        preview.style.display = 'block'
        console.log(`Cropped ${state.fileName}: ${blob?.size} bytes`)
    })

    button.addEventListener('click', () => cropper.open())
</script>

Custom Styling

You can override default CSS classes:

const cropper = HqCropper(
    onSubmit,
    {},
    {
        root: ['my-cropper'],
        portal: ['my-portal'],
        applyButton: ['btn', 'btn-primary'],
        cancelButton: ['btn', 'btn-secondary'],
    }
)

Available CSS class overrides:

| Class | Element | | -------------------------- | -------------------------- | | root | Root container | | header | Header with filename | | body | Main content area | | footer | Footer with buttons | | portal | Crop selection area | | portalArea | Portal container | | sourceImage | Source image | | preview | Preview container | | previewImage | Preview image | | applyButton | Apply button | | cancelButton | Cancel button | | handlerMove | Move handle | | handlerResizeTopLeft | Top-left resize handle | | handlerResizeTopRight | Top-right resize handle | | handlerResizeBottomLeft | Bottom-left resize handle | | handlerResizeBottomRight | Bottom-right resize handle |

TypeScript Support

Full TypeScript support with exported types:

import type {
    HqCropperInstance,
    ConfigurationOptions,
    ClassNames,
    ApplicationState,
    ErrorHandler,
} from 'hq-cropper'

Fonts

HQ-Cropper does not define any font-family. The cropper inherits the font from your application's CSS, ensuring seamless integration with your design system.

/* Your app's CSS */
body {
    font-family:
        Inter,
        -apple-system,
        BlinkMacSystemFont,
        'Segoe UI',
        sans-serif;
}

/* The cropper will automatically inherit this font */

To override fonts specifically for the cropper:

const cropper = HqCropper(
    onSubmit,
    {},
    {
        container: ['my-cropper-container'],
    }
)
.my-cropper-container {
    font-family: 'Custom Font', sans-serif;
}

Browser Support

Works in all modern browsers that support:

  • ES2020+
  • Canvas API
  • FileReader API
  • Touch events (mobile)

License

MIT © Iakov Salikov