> ## Content Index
> Fetch the complete content index at: https://atomic-noggin-bloggin.ghost.io/llms.txt
> Use this file to discover other available public pages before exploring further.

# Look Ma! My first NPM package!
- URL: https://atomic-noggin-bloggin.ghost.io/look-ma-my-first-npm-package/
- Published: 2026-09-03T12:41:29.000Z
- Updated: 2026-09-03T15:00:46.000Z
- Author: Patrick Denny

I guess it's sort of weird that even though I've been working in Web Dev for as long as I have, I've never published my own NPM Package. Most of my development has been owned by employers or clients I worked for at the time. The few little side-projects I've produced never moved beyond scratching a specific itch, or been relegated to codepen.io experiments. But after ruminating on an idea for over a decade, I've finally created something I think is worthy of publishing

Have you ever wanted a way to automatically add JS to HTML elements based on an element's set attributes, attribute values, class names, or even just a query selector? Would you like it to work with custom attributes as well as standard ones? Work with both DOM and Shadow DOm elements? Update in real time? Be extremely flexible and customizable? Framework agnostic? Vanilla JS (with Typescript types defined)?  
  
Would also help if it was a single file, zero dependancy ESM module? 

Well, I have a solution for you. 

## **npm install custom-behavior-registry**

  
First some history. This idea isn't new; Many other people have had similar thoughts. This project was inspired by other packages and developers that built similar functionality:

- [WebReflection / wicked-elements](https://github.com/WebReflection/wicked-elements?ref=atomic-noggin-bloggin.ghost.io) Attaches one or more behavior objects to any element that matches an object's associated query selector. CustomBehaviorRegistry is a spiritual successor of sorts to this package.
- [matthewp / custom-attributes](https://github.com/matthewp/custom-attributes/?ref=atomic-noggin-bloggin.ghost.io) Attaches one or more behavior classes to any element that have an associated custom attribute defined.
- [lume / element-behaviors](https://github.com/lume/element-behaviors?ref=atomic-noggin-bloggin.ghost.io) Attaches one or more behavior classes to any element with an assocated name in a space delimitated list within the non-standard 'has' attribute.

There's even an old [Webcomponents/Custom Attributes](https://github.com/WICG/webcomponents/issues/1029?ref=atomic-noggin-bloggin.ghost.io) proposal that was resurfaced by [Jake Archibald on Bluesky](https://bsky.app/profile/webdevs.firefox.com/post/3m6wnagqrss22?ref=atomic-noggin-bloggin.ghost.io) a few month back. This post is what made me revisit the idea of a behavior registry and really nail down the specifics. 

Adam Argyle also recently announced [Prop-for-that](https://nerdy.dev/prop-for-that?ref=atomic-noggin-bloggin.ghost.io), a project that automatically adds CSS custom properties for many JS-only variables using a list of values in a data-prop-for custom attribute. Essentially a custom behavior triggered by changes to a specific attribute on any DOM element. While his approach is a one-off version of my solution with some additional functionality, it did validate that a tool like mine could be useful for prototyping or building out similar solutions.

## Custom Behavior Registry vs Custom Element

If a Custom Element can be considered as "Extending" the HTMLElement class (or sub classes with the is="" attribute), a Custom Behavior could be seen as an optional "includes" list to the class, only updateable in real time. It gives developers the ability to add one or more behaviors to any element based on their own specified criteria. 

Because every project will have it's own needs, I decided to let developers build their own registries, instead of determining a one size fit's all approach (though I did [sort of create one of those](https://github.com/AtomicNoggin/custom-behavior-registry/tree/main?ref=atomic-noggin-bloggin.ghost.io#combine-all-of-the-above-into-a-custombehaviors-registry) as well) You initially create a new Registry with [**various options and methods to match your specifications**](https://github.com/AtomicNoggin/custom-behavior-registry?ref=atomic-noggin-bloggin.ghost.io#registry-options). 

These settings let you validate behavior naming structure, and determine how an element gets selected for connection. Ultimately it uses a query selector to find which elements to connect a behavior to, but how that query gets generated is entirely up to the developer. There are are optional callback hooks that can fire every time a behavior is defined, or an instance is created, connected, disconnected, or has an attribute updated.

Once a registry is created, it has a very similar, if expanded, API to the custom element registry. You can define a behavior; create promise to resolve once a named behavior gets registered; get the registry class back by name, or registry instance for a given name and element; get all elements connected to a behavior; or all behaviors connected to an element. 

There are even registry management calls, to temporarily pause and restart live updates, update or clear registry settings; and remove registered behaviors.

## Defining a behavior

[Defining behaviors](https://github.com/AtomicNoggin/custom-behavior-registry?ref=atomic-noggin-bloggin.ghost.io#define-a-behavior) works very much like defining an element: create a behavior class with callback methods to follow the lifecycle of behavior as it connects and disconnects from elements. It can even observe the attribute updates of the element it's connected to. 

There are a few key differences

- The Behavior Class doesn't need to extend any builtin classes. This is because the Behavior class does not insert itself into the prototype chain of the element. it lives in it's own little scope. This allows for weak attachments as the behavior connects and disconnects over time.
- Each callback is handed the element as an argument. Instead of forcing each behavior to keep track of their element internally, it made more sense to just hand in the element each time, keeping the association as weak as possible.
- The constructor also gets an options object, should one have been provided at definition time. this allows fine grain customization to be passed in as needed.
- on top of a static list of observed attributes, you can optionally add a static list of tag names (either inclusive, or exclusive) to further limit what elements to attach to. When writing up example behaviors, this was such a common use case, I included it.
- there's also a static preConnectionCheck callback. It is called before a behavior class is first initiated. It can return `false` to skip the connection, `true` to continue, or pass back a new options object to merge with the definition options as needed.
- the connectedMoveCallback is not limited to moveBefore calls. Instead of monkey patching a single method for moves, I found it more convenient to track which behaviors both detached and re-attached within the same Mutation Observer record set.

## Examples

I'll be creating more an more examples as I fond more use cases In fact I have three [Datatable related ones ](https://codepen.io/collection/gPoNge?ref=atomic-noggin-bloggin.ghost.io)I built a while ago. On top of those, I also have the following Intl related ones:

A behavior to [extend the <TIME> tag](https://github.com/AtomicNoggin/custom-behavior-registry/tree/main/examples/intl-time?ref=atomic-noggin-bloggin.ghost.io) to display locale aware date, time & duration details, based on the datetime attribute.

See the Pen [Automatic Intl Date, Time, and Duration Formatting with <time> tag](https://codepen.io/editor/AtomicNoggin/pen/019d5df8-044b-7953-8151-e8fe09fd01bf?ref=atomic-noggin-bloggin.ghost.io) by Patrick Denny ([@AtomicNoggin](https://codepen.io/AtomicNoggin?ref=atomic-noggin-bloggin.ghost.io)) on [CodePen](https://codepen.io/?ref=atomic-noggin-bloggin.ghost.io). 

A behavior to [extend the <DATA> tag ](https://github.com/AtomicNoggin/custom-behavior-registry/tree/main/examples/intl-data?ref=atomic-noggin-bloggin.ghost.io)to display locale aware numeric data.

See the Pen [Automatic Intl Number Formatting with <data> tag](https://codepen.io/editor/AtomicNoggin/pen/01a062d8-4205-79ce-b1ef-3ec243a8ae1f?ref=atomic-noggin-bloggin.ghost.io) by Patrick Denny ([@AtomicNoggin](https://codepen.io/AtomicNoggin?ref=atomic-noggin-bloggin.ghost.io)) on [CodePen](https://codepen.io/?ref=atomic-noggin-bloggin.ghost.io).