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

@bskyprism/character-counter

v0.0.2

Published

Count characters

Readme

Character Counter

tests types module install size gzip size semantic versioning Common Changelog license

A visual character counter web component with a circular progress indicator, inspired by Bluesky's post composer.

See a live demo

Featuring

Install

npm i -S @bskyprism/character-counter

Use

Basic Example

This calls the global function customElements.define. Just import, then use the tag in your HTML.

Import JavaScript

import '@bskyprism/character-counter'

Import CSS

import '@bskyprism/character-counter/css'

Or minified:

import '@bskyprism/character-counter/min/css'

Use in HTML

<character-counter max="300" count="50"></character-counter>

Dynamic Updates

Update the count attribute as the user types:

const textarea = document.querySelector('textarea')
const counter = document.querySelector('character-counter')

textarea.addEventListener('input', () => {
    counter.setAttribute('count', textarea.value.length)
})

Or use the setter:

counter.count = textarea.value.length

Attributes

| Attribute | Type | Default | Description | |-----------|------|---------|-------------| | max | number | 300 | Maximum character count | | count | number | 0 | Current character count | | hide-count | boolean | false | When present, never shows the remaining count text | | warn | boolean | false | When present, only shows count when within 20 of limit (ignored if hide-count is present) |

Display Behavior

The component's text display behavior depends on these attributes:

  • Default (no attributes): Always shows the remaining count
  • With warn: Only shows count when 20 or fewer characters remain
  • With hide-count: Never shows the count (takes precedence over warn)
<!-- Always show count -->
<character-counter max="300" count="50"></character-counter>

<!-- Only show count when near limit -->
<character-counter max="300" count="285" warn></character-counter>

<!-- Never show count -->
<character-counter max="300" count="50" hide-count></character-counter>

Data Attributes

Sets data attributes based on state:

| Attribute | Description | |-----------|-------------| | data-over-limit | Present when count exceeds max | | data-hide-count | Present when count text should be hidden (uses visibility: hidden to prevent layout shift) |

CSS Custom Properties

Customize the appearance using CSS variables:

| Property | Default | Description | |----------|---------|-------------| | --counter-diameter | 2rem | Circle diameter (supports any CSS unit) | | --counter-stroke-width | 4 | Circle stroke width in pixels | | --counter-track-color | #e0e0e0 | Background ring color | | --counter-normal-color | #1d9bf0 | Progress color when under limit | | --counter-warning-color | #f4212e | Progress color when over limit | | --counter-text-color | #536471 | Remaining count text color |

Change size globally

character-counter {
    --counter-diameter: 3rem;
    --counter-stroke-width: 5;
}

Change colors

character-counter {
    --counter-normal-color: #059669;
    --counter-warning-color: #dc2626;
    --counter-track-color: #f3f4f6;
}

Per-instance customization

<character-counter
    max="280"
    count="0"
    style="--counter-diameter: 32px; --counter-normal-color: purple"
>
</character-counter>

Behavior

  • Progress indicator: The circular ring fills as count approaches max
  • Number display: The remaining count appears to the left of the circle (controlled by hide-count and warn attributes)
  • Over-limit state: When count > max, the component turns red and shows a negative number (if count display is enabled)
  • Accessibility: Announces character count to screen readers via ARIA live regions

API

This exposes ESM and common JS via package.json exports field.

ESM

import '@bskyprism/character-counter'
// Named import
import { CharacterCounter } from '@bskyprism/character-counter'

Common JS

require('@bskyprism/character-counter')

TypeScript

The component includes TypeScript definitions and extends the global HTMLElementTagNameMap.

// Type-safe querySelector
const counter = document.querySelector('character-counter')
// counter is typed as CharacterCounter | null

// Set count via property
counter.count = 42

// Get computed values
console.log(counter.remaining)      // number
console.log(counter.isOverLimit)    // boolean
console.log(counter.hideCount)      // boolean
console.log(counter.warn)           // boolean
console.log(counter.shouldShowCount) // boolean

Pre-Built Files

This package exposes minified JS and CSS files. Copy them to a location accessible to your web server, then link to them in HTML.

Copy Files

cp ./node_modules/@bskyprism/character-counter/dist/index.min.js ./public/character-counter.min.js
cp ./node_modules/@bskyprism/character-counter/dist/style.min.css ./public/character-counter.css

Use in HTML

<head>
    <link rel="stylesheet" href="./character-counter.css">
</head>
<body>
    <character-counter max="300" count="0"></character-counter>

    <script type="module" src="./character-counter.min.js"></script>
</body>