Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

css-counter-value

Package Overview
Dependencies
Maintainers
0
Versions
4
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

css-counter-value

Convert CSS counter() values to integers without JavaScript

  • 2.0.1
  • latest
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
18
decreased by-74.65%
Maintainers
0
Weekly downloads
 
Created
Source

Jane Ori - PropJockey.io

css-counter-value from PropJockey

Convert CSS counter() values to integers without JavaScript.

The limiting feature support required to use this utility is timeline-scope.

css-counter-value Features:

  1. Converting any counter() value into an integer for use in calc().
  2. Passing integer value of a counter UP to parents (Giving parents their child count as a --var).
  3. The integer for a counter value can be set from any counter() contextually and be scoped all the way up on :root so the whole site's CSS can mathematically respond to any counter anywhere.
  4. Counter values 0 to 120 supported.
  5. Since counters can count globally unlike :nth-* selectors, elements can now mathematically respond to their GLOBAL index (<= 120).
  6. Style queries then empower decendants of the counter value's scope to respond in any way you can think of, beyond mathematical manipulation.
  7. Need the counter value's scope itself to respond in non-mathematical ways? Run a mathematical comparitor then convert the resulting bit into a Space Toggle using an animation like shown in the demo window here.
  8. No JavaScript involved.

Installation and Setup

$ npm install css-counter-value

Then include /node_modules/css-counter-value/counter-value.css

OR Use your favorite NPM CDN for small projects

From html:

<link rel="stylesheet" type="text/css" href="https://unpkg.com/css-counter-value@2/counter-value.css">
or directly from your CSS:
@import url(https://unpkg.com/css-counter-value@2/counter-value.css);

Usage

Any element on the page can have a maximum of 8 converted counters hosted in its scope, each counter occupying a variable 1 through 8.

var(--counter-value\\1) var(--counter-value\\2) var(--counter-value\\3) var(--counter-value\\4) var(--counter-value\\5) var(--counter-value\\6) var(--counter-value\\7) var(--counter-value\\8)

For example, a td might host its table-row counter (1) and its table-col counter (2).

Additionally, the table might host the value of the counters of the last td, effectively putting two more counters in scope for the rest of the table.

This rapidly enables the table (or grid, lists, etc) to know how many rows and columns it has without writing complex selectors to account for every potential count.

In this scenario, there would still 4 additional counters-values that could be converted in scope of any td on the table.

css-counter-value Example

If you prefer to dive into live code, check out this codepen.

Given this table, or a similarly structured grid, nested lists, or any other DOM tree (noting the inline styles managing the counter states):

<table>
  <thead>...</thead>
  <tbody style="counter-reset: table-row 0;">
    <tr style="counter-increment: table-row 1; counter-reset: table-col 0;">
      <td style="counter-increment: table-col 1;">
        Who am I, really?
      </td>
      <td style="counter-increment: table-col 1;">
        Who am I, really?
      </td>
    </tr>
    <tr style="counter-increment: table-row 1; counter-reset: table-col 0;">
      <td style="counter-increment: table-col 1;">
        Who am I, really?
      </td>
      <td style="counter-increment: table-col 1;">
        Who am I, really?
      </td>
    </tr>
  </tbody>
</table>

To convert a counter into an integer, add a directive as a descendant of the elment being counted and css-counter-value's built in CSS interpreter will assign the output counter-value\\* vars as directed.

By default, without a matching host in a directive's context, the directive will assign the converted counter-value to var 1 (of 8) on its immediate parent, making the parent element an implicit host for the variable its setting:

<table>
  <thead>...</thead>
  <tbody style="counter-reset: table-row 0;">
    <tr style="counter-increment: table-row 1; counter-reset: table-col 0;">
      <td style="counter-increment: table-col 1;">
        Who am I, really?
      </td>
      <td style="counter-increment: table-col 1;">
        <output data-counter-value style="--counter: table-col;"></output>
        Know Thyself...?
      </td>
    </tr>
    <tr style="counter-increment: table-row 1; counter-reset: table-col 0;">
      <td style="counter-increment: table-col 1;">
        Who am I, really?
      </td>
      <td style="counter-increment: table-col 1;">
        <output data-counter-value style="--counter: table-col;"></output>
        Know Thyself...?
      </td>
    </tr>
  </tbody>
</table>

The two td elements with the data-counter-value directive inside of them now hold a CSS var var(--counter-value\\1) with an integer value of 2.

We set the --counter variable to [the name of the counter] we wish to convert using the style attribute inline, but this can be done from your CSS if you prefer.

To add the row number, we must choose a variable slot not already in scope (other than 1 in this case) and add another directive to the td's. To do this, assign the desired number 1 to 8 to the data-counter-value attribute and set --counter to the table-row counter like so:

  <td style="counter-increment: table-col 1;">
    <output data-counter-value style="--counter: table-col;"></output>
    <output data-counter-value="2" style="--counter: table-row;"></output>
    Know Thyself.
  </td>

The two td elements now implicity host a second CSS var var(--counter-value\\2) with an integer value of 1 or 2 depending on which row is looking.

data-counter-value="7" would mean "set var(--counter-value\\7)'s value to [whatever counter name's value is specified]"

If we want our table to know how many rows and cols it contains, we add a explicit host directive attribute values to the table and, in the final td, two directives that set those values based on the counter() states in their td element's scope:

<table data-counter-value="host:3 host:4">
  ...
  <tbody style="counter-reset: table-row 0;">
    ...
    <tr style="counter-increment: table-row 1; counter-reset: table-col 0;">
      ..
      <td style="counter-increment: table-col 1;">
        <output data-counter-value style="--counter: table-col;"></output>
        <output data-counter-value="2" style="--counter: table-row;"></output>
        <output data-counter-value="3" style="--counter: table-col;"></output>
        <output data-counter-value="4" style="--counter: table-row;"></output>
        Know Thyself.
      </td>

Assuming this is the last td in the table, the table and every element inside of it will have access to var(--counter-value\\3) (which contains and integer count of the total number of columns in the last row) and var(--counter-value\\4) (which contains the integer total count of rows in the table).

Any of the 8 counter-value variables can be hosted on any ancestor, even :root, and be set from any counter context within the host element.

[!NOTE] Even though the table-row counter itself is stored on the tbody, the whole tabel has access to its integer counter value now.

Every td can use both of these total count vars without adding the additional directives because the --counter-value\\3 and --counter-value\\4 vars are inherited from table.

[!CAUTION]
Any hosting element (matching data-counter-value*="host:") must not host the same variable as an ancestor. That is, for any given element's scope, it must not have more than one ancestor hosting the same counter-value variable 1 to 8.

[!CAUTION] Within any given host element's context (descendants), there must not be more than one directive trying to set the same counter-value variable.

[!TIP] If your counters for a specific counter-value variable 1 to 8 are all 0 values, the most likely scenario is a violation of either of the previous two rules.

Any number of sibling elements can host all 8 counter-value variables for their own contexts as long as they don't have ancestors or descendants also trying to host one of the 8 variables.

For example, these three scenarios all break for the same reason:

<div data-counter-value="host:1 host:2 host:3">
  <output data-counter-value="2" style="--counter: global-div-counter;"></output>
  1
  <div>
    <output data-counter-value style="--counter: global-div-counter;"></output>
    <!-- note this ^ is setting var 1, not implicitly on the parent, but explicitly to the ancestor hosting var 1 since it exists -->
    2
  </div>
  <div>
    <output data-counter-value style="--counter: global-div-counter;"></output>
    <!-- note this ^ is setting var 1 to the same host, which is a conflict -->
    3
  </div>
</div>

and, very similar:

<div data-counter-value="host:1 host:2 host:3">
  <output data-counter-value style="--counter: global-div-counter;"></output>
  <!-- note this ^ is setting var 1 to its parent because the parent explicitly hosts var 1 -->
  1
  <div>
    <output data-counter-value style="--counter: global-div-counter;"></output>
    <!-- note this ^ is setting var 1 to the ancestor hosting var 1 since one exists -->
    2
  </div>
</div>

and, the tricky one:

<div data-counter-value="host:2 host:3">
  <output data-counter-value style="--counter: global-div-counter;"></output>
  <!-- note this ^ is setting var 1 to its parent implicitly -->
  1
  <div>
    <output data-counter-value style="--counter: global-div-counter;"></output>
    <!-- note this ^ is going to try setting var1 implicitly to its parent but will fail because an ancestor is implicity already hosting it -->
    2
  </div>
</div>

The following example is completely acceptable - there's a wide range of wild, exciting behavior still possible. We can have all sorts of fun within the established boundaries of this relationship, if you want 😉

<html data-counter-value="host:8">
  ...
  <body style="counter-reset: global-div-counter: 0;">
    <style>div { counter-increment: global-div-counter 1; }</style>

    <div data-counter-value="host:3">
      <output data-counter-value="2" style="--counter: global-div-counter;"></output>
      <!-- var 2, implicitly on parent -->
      1
      <div>
        <output data-counter-value style="--counter: global-div-counter;"></output>
        <!-- var 1, implicitly on parent -->
        2
      </div>
      <div>
        <output data-counter-value style="--counter: global-div-counter;"></output>
        <!-- var 1, implicitly on parent -->
        <output data-counter-value="3" style="--counter: global-div-counter;"></output>
        <!-- var 3, explicitly on an ancestor -->
        3
      </div>
    </div>

    <div data-counter-value="host:3">
      <output data-counter-value="2" style="--counter: global-div-counter;"></output>
      <!-- var 2, implicitly on parent -->
      4
      <div>
        <output data-counter-value style="--counter: global-div-counter;"></output>
        <!-- var 1, implicitly on parent -->
        5
      </div>
      <div>
        <output data-counter-value style="--counter: global-div-counter;"></output>
        <!-- var 1, implicitly on parent -->
        <output data-counter-value="3" style="--counter: global-div-counter;"></output>
        <!-- var 3, explicitly on an ancestor -->
        6
      </div>
    </div>

    <div data-counter-value="host:3">
      <output data-counter-value="2" style="--counter: global-div-counter;"></output>
      <!-- var 2, implicitly on parent -->
      7
      <div>
        <output data-counter-value style="--counter: global-div-counter;"></output>
        <!-- var 1, implicitly on parent -->
        8
      </div>
      <div>
        <output data-counter-value style="--counter: global-div-counter;"></output>
        <!-- var 1, implicitly on parent -->
        9
      </div>
      <div>
        <output data-counter-value style="--counter: global-div-counter;"></output>
        <!-- var 1, implicitly on parent -->
        10
      </div>
      <div>
        <output data-counter-value style="--counter: global-div-counter;"></output>
        <!-- var 1, implicitly on parent -->
        <output data-counter-value="3" style="--counter: global-div-counter;"></output>
        <!-- var 3, explicitly on an ancestor -->
        <output data-counter-value="8" style="--counter: global-div-counter;"></output>
        <!-- var 8, explicitly on :root, giving the whole document access to a variable var(--counter-value\\8) === 11 -->
        11
      </div>
    </div>

Oh, and if you're setting multiple counter-value variables with the same counter source, you can just use one directive instead.

  <div>
    <output data-counter-value style="--counter: global-div-counter;"></output>
    <!-- var 1, implicitly on parent -->
    <output data-counter-value="3" style="--counter: global-div-counter;"></output>
    <!-- var 3, explicitly on an ancestor -->
    <output data-counter-value="8" style="--counter: global-div-counter;"></output>
    <!-- var 8, explicitly on :root, giving the whole document access to a variable var(--counter-value\\8) === 11 -->
    11
  </div>

becomes

  <div>
    <output data-counter-value="1 3 8" style="--counter: global-div-counter;"></output>
    <!-- var 1, implicitly on parent -->
    <!-- var 3, explicitly on an ancestor -->
    <!-- var 8, explicitly on :root, giving the whole document access to a variable var(--counter-value\\8) === 11 -->
    11
  </div>

Have fun!

Open Contact 👽

Please do reach out if you need help with any of this, have feature requests, want to share what you've created, or wish to learn more.

PropJockey.ioCodePenDEV BlogGitHubMastodon
PropJockey.ioCodePenDEV BlogGitHubMastodon

🦋@JaneOri.PropJockey.io

𝕏@Jane0ri

Keywords

FAQs

Package last updated on 31 Dec 2024

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc