Nerds Publishing Monstrosities

    TypeScript icon, indicating that this package has built-in type declarations

    2.0.1 • Public • Published


    npm semver codecov CI DL/month

    A slim CSS Counter Styles Level 3 compliant library with 47 presets including
    Arabic, Persian, Thai, Hebrew, Roman, Katana...

    The core is less than 1.7kB minified and gzipped.
    Each preset is distributed as a separate module.
    Available in both CommonJS and ECMAScript modules.
    Targets ECMAScript 2015.
    Optimized for metro (React Native) and Webpack bundlers.
    Based on prior work from Whang Shuwei.


    npm add --save @jsamr/counter-style
    yarn add @jsamr/counter-style

    Using presets

    This library exports 47 presets. Find your preset here. Each preset is accessible in a separate module to limit bundle size.

    import arabicIndic from '@jsamr/counter-style/presets/arabicIndic';
    expect(arabicIndic.renderMarker(78)).toBe('٧٨. ');

    PRs are welcomed to support other presets. Very easy to implement thanks to this W3C resource.

    Creating custom style renderers

    The API follows closely the specs for CSS @counter-style at rule. The default export (CounterStyle) is a static object with methods to build CounterStyleRenderer.

    Example 1: a lower Russian alphabet renderer

    In the below example, we're using the alphabetic counter system and alphabeticFromUnicodeRange builder which allows to specify a contiguous unicode range. For non-contiguous ranges, use the alphabetic builder.

    import CounterStyle from '@jsamr/counter-style';
    const lowerRussian = CounterStyle.alphabeticFromUnicodeRange(
      0x430, // а
    ).withSuffix(') ');
    // Expect comes from jest testing framework.
    // Just a showcase of expected returned values.
    expect(lowerRussian.renderMarker(1)).toBe('а) ');
    expect(lowerRussian.renderMarker(4)).toBe('г) ');
    expect(lowerRussian.renderMarker(5)).toBe('д) ');
    expect(lowerRussian.maxMarkerLenInRange(1, 5)).toBe(3);
    expect(lowerRussian.maxCounterLenInRange(1, 5)).toBe(1);

    Reference: W3C Ready-made Counter Styles: Cyrillic styles.

    Example 2: a "Funky" symbolic renderer

    In the below example, we're using the symbolic counter system. Note that withSuffix(null) removes default suffix.

    import CounterStyle from '@jsamr/counter-style';
    // Default suffix is ". ", as per the specs.
    const funky = CounterStyle.symbolic('*', '&').withSuffix(null);
    // Expect comes from jest testing framework.
    // Just a showcase of expected returned values.
    expect(funky.maxMarkerLenInRange(1, 5)).toBe(3);
    expect(funky.maxCounterLenInRange(1, 5)).toBe(3);

    All renderers can be chained to create variants, such as withSuffix, withPaddingLeft, ... See available methods in the docs.

    API reference

    The API reference is available here.


    • Instead of a normal space character, a non-breaking space is used for default prefixes. This is because this library primary usage is for React Native. On iOS, Text elements get trimmed of normal space characters.
    • In numeric and alphabetic systems , one UTF-16 code unit per symbol must be used. Otherwise, length computation will be erroneous. If you really need multi code units per symbol however, you can still set a custom length computer via withMaxLenComputer.
    • When using padding (withPadding) and negative (withNegative) symbols, one UTF-16 code unit per symbol must be used. Otherwise, length computation will be erroneous.
    • Never use combining characters. Grapheme clusters will be considered distinct characters. Beware that is the case for some emojis, see this SO thread.
    • Don't define incomplete additive systems which have holes in their range coverage. For example, an additive system which has no representation for "1" will not translate odd indexes.


    • speakAs hasn't been implemented yet.
    • Chinese renderers haven't been implemented, requiring custom logic. PRs welcomed!
    • Only textual symbols are supported. Images are not.


    npm i @jsamr/counter-style

    DownloadsWeekly Downloads






    Unpacked Size

    376 kB

    Total Files


    Last publish


    • jsamr