bitty
Introduction
bitty is a web component. Wrapping it around other elements makes them interactive. For example, click/tap this button a few times in differnet places to get the coordinates of where the interaction occurred:
Here's the code behind the functionality:
Get Click Coordinates
waiting
How It Works
bitty uses signals to associate events with elements. They're connected through methods you write to provide functionality. For example:
- sends
a signal named
coordswhen it's clicked -
receives
coordssignals sets the . value of the to the . and . values from the click event of thecoordssignal.(Signal names map to method names which is why this one is named
coords.)
That's pretty much it. bitty has some helper functions. They do things like load external HTML, JSON, and SVG files, etc... but that's all secondary. At its core, bitty sets you up to create your functionality and then gets out of the way.
Installation / Getting Started
TL;DR
This section walks through making these two files. If you just want to see them work you can copy the contents, adjust the paths as necessary, and drop them on your site.
Get Random Number
The result is this button that updates with a random number:
The Walk-Through
The <script> Tag
bitty is a web component. Including it on your page
is done with a script tag:
- download the bitty-5.0.0.min.js file
- put the file somewhere in your site's directory tree
load bitty on your pages with a script tag like:
Making a Functionality Class
bitty works by connection to a class
that provides methods for functionality. For example,
here's a module that exports a default class
with a randomNum() method in it.
Connecting to the Functionality Class
Here's an empty bitty tag that
uses the data-connect attribute to
connect to the default export class from the module:
<!-- child elements go here -->
Creating an Interactive Element
Next up is a button element with
data-send and data-receive
attirubtes. Both use randomNum
as their value to line up with the method
from the module
Get Random Number
Putting It All Together
Here's the completed HTML with the button in place:
Get Random Number
And here's the module file again to see it in context
And here's the live result:
Next Steps
The example in the overview used a button with
a data-send attribute and a separate div
with a data-receive attribute. Here, we're using
a single button with both data-send and data-receive.
No extra work is required for most elements to
both send and receive the same signal.
There are some cases (like elements)
where you have to add check to prevent feedback. bitty
provides helper funtions including one called match
to cover that. Check out the Docs sections
below for details. You can also check out the Test Suite.
Each test includes its source code that work as their own
examples as well.
Docs - The HTML data-* API
bitty sends signals to elements when
events occur. Defining the signals and the events
that trigger them is done with four data-*
attributes that are added to
tags and their children. The four attributes are:
data-connect
Defines the class that provides functionality to the component.
Availability: elements: yes - child elements: no
Each requires an external class to provide its functionality. The class can reside in one of four locations:
If there is no
data-connectattribute on the<bitty-5-0>component tag, then bitty looks for awindow.variable. For example:index.htmlGet Random NumberExample(NOTE: the check is generally not necessary. It's used here because of the tests further below. The one that tests window. throws an erroneous error without it.)
-
If the
data-connectattribute exists and its value matches a variable on thewindowobject, then theclassfrom that variable is used. For example:index.htmlGet Random NumberExample The default export from an external module when the value of `data-connect` is the path to the module. For example:
index.htmlGet Random Number/v5.0.0/modules/data-connect-default-class.jsExampleA named class from an external module when the value of `data-connect` is a path followed by a space then the name of the class to look for. For example:
index.htmlGet Random Number/v5.0.0/modules/data-connect-alt-class.jsAltModuleClassExample
data-listeners
Availability: elements: yes - child elements: no
The data-listeners attribute changes the events a component listens for. The default events are `click` and `input`. Changing it to listen to `mouseenter` looks like this:
Move Mouse Over
-
Multiple listeners can be added by separating them with a space:
Move Mouse Over
-
Using `data-listeners` remove the default `click` and `input` listeners. They can be added back in explicitly if needed.
Move Mouse Over or Click
-
data-receive
Availability: bitty-5-0 elements: no - child elements: yes
Adding a `data-receive` attribute to an element sets it up to receive signals with the given name.
Click For Random Number
-
Multiple elements can receive the same signal. Each one gets passed through the corresponding function individually (i.e. a different random number is generated for each):
Click For Random Number
-
-
-
A single element can receive multiple signals by separating the signal names with a space in the `data-receive` attribute:
Send Alfa
Send Bravo
Send Charlie
-
data-send
Availability: bitty-5-0 elements: yes - child elements: yes
Sending Single Signals
The `data-send` attribute defines which signals an element sends when an event that's being listend for fires.
Click For Random Number
-
Sending Multiple Signals
A single element can send multiple signals by separating them with a space in the `data-send` attribute:
Send Multiple Signals
-
-
-
Sending From the <bitty-5-0> tag
A `data-send` attribute can be added to the bitty-5-0 component tag itself. It create a custom `bittytagdatasend` event that only fires once after the component has been initialized:
-
Sending Without Receivers
If an event triggers a `data-send` signal and there are no matching `data-receive` elements, then the corresponding method is fired once with a `null` value for the element. For example:
Increment
-
This is useful when the number of times an update needs to occur differers from the number of receiving elements. For example, incrementing by one works if a button is connected to only one element with a matching `data-receive` attribute:
Increment
-
If there are multiple receivers, each one increments the `#count` on its own. For example, every click of this button adds one to each output so they end up with `1, 2, 3`, then `4, 5, 6`, etc...
Increment
-
-
-
Sending an individual signal to do the incrementing that isn't associated with an `data-receive` elements followed by a signal that _is_ connected to them keeps them in sync
Increment
-
-
-
async Signal Methods
Signal Methods can be `async`
Send Signal
-
(NOTE: There's currently not a way to do an `await` from `data-send`. That's coming in a future release.)
Docs - Signal Method API
Signals names are mapped to method names in the class that provides funcionality to the component. Check out the demo in the overview for a basic example.
The bitty element is exposed to
the class providing functionality via
this.. The bitty component adds the following
supplemental methods to the standard
element methods and properties.
forward(event, signal)
- calls another method to trigger its signal. The event which triggered the first signal can be sent to the second.
event
The event to forward, can be null.
signal
The name of the signal to forward to (required)
this.api.forward() - Basic Forwarding
Forward Event For Coords
waiting (first)
waiting (second)
this.api.forward() - Forwarding a null event
Forward null Event
waiting (alfa)
waiting (bravo)
getElement(url, subs = [], options = {})
-
Requests and external file as a string of text.
-
Any optional
optionskey/value pairs are passed to the request. -
If the request succeeds, any find/replace patterns from the optional
subsargument are applied. -
A
templateelement is then created. -
The
.innerHTMLvalue of the template is set to the string. -
The template is cloned to produce a document fragment.
-
The
.firstChildelemnet of the document fragment is extrated and return as an HTML Element in an object (i.e.{ ok: ELEMENT }). -
If there's an error the return value is at object with the bitty error (i.e.
{ error: BITTY_ERROR }).
url
The URL of the file to get as a string
subs
An array of arrays for substitutions to make
options
Options to pass to the `.fetch()` method
this.api.getElement() - Basic Element Retrieval
the quick brown fox
Get Element
waiting
this.api.getElement() - Error Handling
Get Element
waiting
this.api.getElement() - Passing Options to .fetch()
the quick brown fox
Get Element
waiting
this.api.getElement() - RegEx Find/Replace
the SPEED KIND fox
Get Element
waiting
this.api.getElement() - String Find/Replace
the SPEED KIND fox
Get Element
waiting
getHTML(url, subs = [], options = {})
-
Requests and external file as a string of text.
-
Any optional
optionskey/value pairs are passed to the request. -
If the request succeeds, any find/replace patterns from the optional
subsargument are applied. -
A
templateelement is then created. -
The
.innerHTMLvalue of the template is set to the string. -
The template is cloned to produce a document fragment.
-
The document fragment is returned in an object with an
okkey (i.e.{ ok: DOCUMENT_FRAGMENT }. -
If there's an error the return value is at object with the bitty error (i.e.
{ error: BITTY_ERROR }).
url
The URL of the file to get as a string
subs
An array of arrays for substitutions to make
options
Options to pass to the `.fetch()` method
this.api.getHTML() - Basic Document Fragment Retreival
Get HTML
waiting
the quick
brown fox
this.api.getHTML() - Error Handling
Get HTML
waiting
this.api.getHTML() - Passing Options to .fetch()
Get HTML
waiting
this.api.getHTML() - RegEx Find/Replace
Get HTML
waiting
the SPEED
KIND fox
this.api.getHTML() - String Find/Replace
Get HTML
waiting
the SPEED
KIND fox
getJSON(url, subs = [], options = {})
-
Requests and external file as a string of text.
-
Any optional
optionskey/value pairs are passed to the request. -
If the request succeeds, any find/replace patterns from the optional
subsargument are applied. -
The string is parsed with
JSON.parse() -
If the parsing succeeds, the resulting object is returned as the value of an
okkey in a response object (i.e.{ ok: OBJECT_FROM_JSON }). -
If there's an error retrieving the file are parsing the JSON a bittyError is returned as the value of an
errorkey in the object that's returned: (i.e.{ error: BITTY_ERROR }).
url
subs
options
this.api.getJSON() - Basic JSON Retrevial
{
"text": "The quick brown fox"
}
Get JSON
waiting
this.api.getJSON() - Error Handling
Get JSON
waiting
this.api.getJSON() - Passing Options to .fetch()
Get JSON
waiting
this.api.getJSON() - RegEx Find/Replace
{
"text": "The SPEED KIND fox"
}
Get JSON
waiting
this.api.getJSON() - String Find/Replace
{
"text": "The SPEED KIND fox"
}
Get JSON
waiting
getSVG(url, subs = [], options = {})
-
Requests and external file as a string of text.
-
Any optional
optionskey/value pairs are passed to the request. -
If the request succeeds, any find/replace patterns from the optional
subsargument are applied. -
A
templateelement is then created. -
The
.innerHTMLvalue of the template is set to the string. -
The template is cloned to produce a document fragment.
-
The
svgelemnet of the document fragment is extrated and return as an HTML Element in an object (i.e.{ ok: ELEMENT }). -
If there's an error the return value is at object with the bitty error (i.e.
{ error: BITTY_ERROR }).
url
The URL of the file to get as a string
subs
An array of arrays for substitutions to make
options
Options to pass to the `.fetch()` method
this.api.getSVG() - Basic SVG Retrevial
Get SVG
waiting
this.api.getSVG() - Error Handling
Get SVG
waiting
this.api.getSVG() - Passing Options to .fetch()
Get SVG
waiting
this.api.getSVG() - RegEx Find/Replace
SVG RegEx Example
The SPEED KIND fox
Get SVG
waiting
this.api.getSVG() - String Find/Replace
SVG Sub Example
The SPEED KIND fox
Get SVG
waiting
getTXT(url, subs = [], options = {}, incomingMethod = "getTXT")
-
Retreives an external file as a string of text
-
Performs find and replace updates from the
subsargument -
Returns the updated content as a string
url
subs
options
incomingMethod
The method that's using getTXT so it can be displayed in errors if they occur
this.api.getTXT() - Basic TXT Retrieval
Get TXT
waiting
The quick brown fox
this.api.getTXT() - Error Handling
Get TXT
waiting
this.api.getTXT() - Passing Options to .fetch()
Get TXT
waiting
the quick brown fox
this.api.getTXT() - RegEx Find/Replace
Get TXT
waiting
The SPEED KIND fox
this.api.getTXT() - String Find/Replace
Get TXT
waiting
The SPEED KIND fox
loadCSS(url, subs, options)
-
Requests and external file as a string of text.
-
Any optional
optionskey/value pairs are passed to the request. -
If the request succeeds, any find/replace patterns from the optional
subsargument are applied. -
A new
CSSStyleSheetis created with the contents of the text added to it via.replaceSync() -
The stylesheet is added to the page with
document.adoptedStyleSheets.push() -
If there are no issues, the text value is returned in
{ ok: TEXT_STRING }. -
If there's an error the return value is at object with the bitty error (i.e.
{ error: BITTY_ERROR }).
url
The URL of the file to get as a string
subs
An array of arrays for substitutions to make
options
Options to pass to the `.fetch()` method
this.api.loadCSS() - Basic CSS Loading
Load CSS
[data-receive=loadCSSBasic] {
color: red;
}
this.api.loadCSS() - Error Handling
Load CSS
this.api.loadCSS() - Passing Options to .fetch()
Load CSS
this.api.loadCSS() - RegEx Find/Replace
Load CSS
[data-receive=loadCSSRegEx] {
color: COLOR_NAME;
}
this.api.loadCSS() - String Find/Replace
Load CSS
[data-receive=loadCSSSubs] {
color: COLOR_NAME;
}
makeElement(template, subs = [])
-
NOTE: This is being renamed from
makeElementtomakeElin v3.x.x -
Produces an HTML element from a string of text.
-
Performs find/replace updates from the
subsparameter on thecontentstring. -
Creates a
templateand sets its.innerHTMLto the value of the updatedcontentstring. -
Clones the
templateand gets its.firstChildwhich is the returned as an element.NOTE: Only one element is retured. If the text snippet has more than one elemnet as sibling at the top level only the first one is returned.
template
The template string to use to make the element
subs
this.api.makeElement() - Make an HTML from a string
Make Element
waiting
this.api.makeElement() - Make an HTML Element from a string with RegEx Find/Replace
Make Element
waiting
this.api.makeElement() - Make an HTML Element from a string with string based Find/Replace
Make Element
waiting
makeHTML(template, subs = [])
-
Performs find/replace updates from the
subsparameter on thecontentstring. -
Creates a
templateand sets its.innerHTMLto the value of the updatedcontentstring. -
Clones the template and returns the result as a document fragment.
template
The template string to use to make the fragment
subs
this.api.makeHTML() - Make a fragment from a string
Make HTML
waiting
this.api.makeHTML() - Make a fragment from a string with RegEx Find/Replace
Make HTML
waiting
this.api.makeHTML() - Make a fragment from a string with string Find/Replace
Make HTML
waiting
match(event, el, key = null)
-
Compares the
.targetfrom aneventand an element to see if they match on a givendataset/data-*key. -
If no
keyis provided the automatically generateduuidis used. -
The return value is
trueif there is a match andfalseif there isn't
event
el
key
this.api.match() - Match on data-uuid
Check
Check
Check
this.api.match() - Match on data-KEY
waiting
waiting
waiting
Click To Compare
Docs - Misc.
Initialization Steps
When a web component (like bitty) is attached to a page's DOM it fires a `connectedCallback` event. bitty uses the event to do the following notable steps in this order:
- load supplemental function into `this.api.fn`.
- automatically generate `data-bittyid` attributes with unique IDs for the bitty element and all children elements if they don't already exist.
- Attempt to make a connection to a supporting class either on the page or in an external module file. If the connection can't be made, an error is thrown and the process stops. Otherwise, the following steps are taken:
- Find any child elements with `data-receive` attributes and add them to the internal list of receivers.
- Add a mutation observer that watches for changes and refreshes receivers when new elements are added or removed. New elements also receive a `data-bittyid` if they don't already have one.
- Add event event listeners at the document level. The defaults are `click` and `input` but can be changed with a `data-listeners` attribute on the bitty component tag.
- Check for a `bittyInit()` method in the connected class and call it if it exists. (If the method is defined with `async bittyInit()` it is called with `await`.)
- Check for a `data-send` attribute on the `bitty` component tag. Trigger it to send its signals if it exists. The signal is set with a type of `bittytagdatasend`. The target is the bitty element itself.
bitty this proceeds to listen for events and send signals when they are triggered.
bittyInit()
Basic Example
async Example
Block Styling
An adoptedStyleSheets is added to the page that sets:
}
Custom data-* Attributes
bitty uses native `data-*` attributes for set up. It's also designed to work with arbitrary `data-*` attributes. Specifically, the `this.api.match` helper function compares `event.target.dataset.KEY` and `el.dataset.KEY` for matches.
UUIDs for Elements
Every bitty component and all their child elements automatically receive a `data-bittyid` attribute with a UUID. They can be used any time an ID is needed. They are also the default values that are compared via `this.api.match(event, el)` if no other key is provided.
UUIDs for Events
The event listeners that bitty uses add a `.bittyid` property to each event. They can be used to prevent processing the same event multiple times in situations where that might occur.
No Events From the Bitty Component
bitty components send a one time `bittytagdatasend` with signals from a `data-send` attribute if one exists. Other than that, no events from the bitty component itself are used. This helps avoid duplication from events that would otherwise bubble and trigger twice.
bittyCatch(event)
Some events don't come from element and don't have
an approachable way to add a data-send
attribute to them (e.g. `.postMessage()`). These events
are captured by an optional bittyCatch(event)
method. The can be adjusted and used to trigger signals
by using this.api.forward()
Release Notes
Version 5.0.0
Nov. 7, 2025
This is a collection of renames for clarity
and to help avoid collisions with
other code that might add data- attributes.
No actual functionality is changed, but
the renames require a version number
bump.
-
Renamed
getElementstogetHTMLfor clarity. (getElementremains the same and pulls individual HTML elements vsgetHTMLwhich pulls document fragments.) -
Renamed
makeElementstomakeHTMLfor clarity. (makeElementremains the same and makes individual HTML elements vsmakeHTMLwhich makes document fragments.) -
Renamed
response.oktoresponse.valuefor clarity and to avoid confusion with things likeresponse.ok === false. (i.e.response.value === falsetakes less mental overhead) -
Renamed
data-uuidtodata-bittyidto namespace and prevent collisions with anything else the wants to usedata-uuid
Version: 4.0.0
Nov. 6, 2025
- Bumping the version number. No changes since v4.0.0-rc1.
Version: 4.0.0-rc1
Oct. 30, 2025
-
Renamed
this.api.getFragmenttothis.api.getElements(this is a breaking change so it's a major version bump) -
Renamed
this.api.makeFragmenttothis.api.makeElements(with thethis.api.getFragmentchange) -
Added
bittyCatch(event)that catches any events that don't have a.target.dataset.sendvalue. This provides a way to catch message like from.postMessage()and decided what to do with them. -
Removed the
this.api.fnset up. It's not worth the overhead compared to just using functions directly. -
Using a space instead of a
|to separate signals and class names. This mimicsclass="some things"from CSS and is easier to type. Each keys must be a set of characters without spaces so there's no need for an explicit|. -
Changed listeners to be on the window to catch things like
.postMessage(). TODO: Make sure that's cool to listen on the window instead of the document. -
Changed internal use of
event.target.dataset.forwardkey forthis.api.forwardtoevent.bitty.forwardto avoid collisions on theevent.target.dataset -
Fixed bug in
this.api.forwardwhere an event that doesn't have a.targetor.target.datasetgets overridden. -
UUID are added to events that are being forwarded if they don't already exist.
-
Migrated docs site to use variables to make it easier to upgrade versions moving forward.
Version: 3.0.0
Oct. 26, 2025
This isn't a huge jump from Version 2.x, but there are breaking changes so it gets a new number. These are quality of life improvements that make it easier to get external content while providing better errors if something goes wrong.
The details:
-
Did the following renames and additions for consistent API names for getting and adding documet fragments and elements:
-
Renamed
this.api.getHTML()tothis.api.getFragment()which pulls in an external file and returns it as a document fragment. -
Added
this.api.getElement()which pulls in an external file and retuns it as a single HTML Element (if there's more than one node at the top of the file only the first one gets returned). -
Renamed
this.api.useTemplate()tothis.api.makeFragment()which takes a string to use as a template and returns a document fragment. -
Added
this.api.makeElement()which takes a string to use as a template and returns a single HTML Element.
-
-
TODO: Added
getCSS()which pulls an external CSS file and loads it into the document as an adopted stylesheet. -
Added custom BittyError class for better error handling with
this.api.getTHINGcalls that use.fetchand for JSON parsing errors. -
When returning values from fetches return an object with either
{ ok: PAYLOAD }, or{ error: { /* details */ } }with extra data coming down in the error object like status codes for HTML errors. -
Added
connectedMoveCallback()to preventconnectedCallback()from firing if a component is moved. -
Moved everything in the init into the conditional check to see if the component makes a connection to a class. Previous a few things happend prior to the connection attempt. Moving them in prevents UUIDs from being added until a conneciton has been made. Shouldn't make any real difference. It just feels more natural.
-
Added and refined the test suite for increased coverage.
Version: 2.0.0-rc2
Oct. 21, 2025
-
Properly returned
undefinedif there's a problem pulling an external HTML from getHTML(). -
Properly returned
undefinedif there's a problem pulling an external JSON from getJSON(). -
Properly returned
undefinedif there's a problem pulling an external SVG from getSVG(). -
Properly returned
undefinedif there's a problem pulling an external TXT from getTXT().
Version: 2.0.0-rc1
Oct. 19.2025
-
Renamed
this.api.fetchJSON()tothis.api.getJSON()to match case used withJSON.stringify(), and switch fromfetchtogetprelude. -
Added substitutions param to
this.api.getJSON(url, subs=[])so all.getTHING(url, subs=[])methods have the same behavior. -
Added
options={}tothis.api.getJSON()to pass options to the fetch call. The signature isthis.api.getJSON(url, subs=[], options={}). -
Added
this.api.getHTML(url, subs=[], options={})that loads an HTML file and does find replace withsubson the initial string wheresubsis an array of arrays with the patterns to match and replace. The patterns can be strings or regex. -
Added
this.api.getSVG(url, subs=[], options={})that loads an SVG file and does find replace withsubswhich is an array of arrays with the patterns to match and replace. The patterns can be strings or regex. -
Added
this.api.getTXT(url, subs=[], options={})that returns the text content of an external file. -
Switched to array or arrays for find replace strings for
this.api.useTemplate(templateString, subs=[])and defaulting to an empty array so the argument doesn't have be sent which is consistent with the.getTHING(url, subs=[]) -
Added an adoptedStylesheet that sets the
<bitty-x-x>tag todisplay: block. -
Added
this.api.match(event, el, key=""). If a key exists, it's used to check thedatasetof theeventand theeland returns true if they match. If nokeyis provided theuuidof theeventandelare compared instead. -
Allowing whitespace around
data-sendattributes. -
Allowing whitespace around
data-receiveattributes. -
Added
.useHTML(content, subs = [])that converts a string fromcontentinto an HTML template (doing the substitutions) then returns the first element from it as an HTML element instead of a document fragment. -
Ingesting
window.bittyFunctionsfrom the page andconst functionsinside the module and providing access the them viathis.api.fn.FUNCTION() -
Ingest local
const functionsfunctions from the bitty component file that get added asthis.api.fn.FUNCTION() -
Ingested functions are bound with
.bind()so that theirthis.is the bitty component's element itself. -
Combined
this.configandthis.metadatain theconstructor().
Version: 1.3.0
Oct. 13, 2025
- Releasing v1.3.0. No changes from v1.3.0-rc1.
Version: 1.3.0-rc1
Oct. 6, 2025
-
Added
fetchJson(url)method which can be called withthis.api.fetchJson(url). Returns the data object if everything works. Otherwise, throws an error and returnsundefined. -
Added
useTemplate()to assemble a example while doing a find and replace of text
Version: 1.2.0-rc1
Oct. 6, 2025
-
When using
data-connectif the value matches a class on the window object it's used. For example:data-connect="ExampleClass"connects towindow.ExampleClass.Previously, the class had to be in a
window.bittyClassesobject (e.g.window.bittyClasses = { ExampleClass: class {} };
Version: 1.1.0-rc2
Oct. 6, 2025
- Updated console error message if no class to connect to can be found.
Version: 1.1.0-rc1
Oct. 4, 2025
-
<bitty-COMPONENT_VERSION>can be called without adata-connectattribute. When it is, it looks for awindow.BittyClasson the page and uses it if it's available. -
Removed .error() method in favor of calling
console.error()directly in order to get useful line numbers.
Version: 1.0.0
Oct. 4, 2025
-
Moved
v1.0.0-rc5tov1.0.0 -
Tag name is
<bitty-1-0>
Version: 1.0.0-rc5
Oct. 4, 2025
-
Fixed bug with events not being passed to signal processing.
Version: 1.0.0-rc4
Oct. 1, 2025
-
Renamed
<bitty-js>component tag to<bitty-MAJOR_VERSION>for semantic versioning. -
Call
bittyInit()withawaitif it's anasyncfunction. -
Moved
bittyInit()before thedata-sendcalls from the component so the module can set things up before the signals start being sent. -
Allowing
this.api.forward()to be called with anullevent (e.g.this.api.forward(null, "anotherFunction");). This is done to allow things like forwarding a signal frombittyInit()or any other function where there isn't an event to pass along. -
Fixed bug where new receivers weren't being added properly when they were child nodes of new nodes being added (and the top layer didn't have a
data-attr in it) -
Added tests for
this.api.querySelector()anddocument.querySelector() -
Update site to use variables for version numbers to make them easier to maintain instead of having them in multiple places for different displays.
-
Made
this.metadataan object and movedversioninto it (along withcopyrightandlicense)
Version: 1.0.0-rc3
Sept. 23, 2025
-
Fixed bug where
this.api.send()would update thedata-sendattribute on the original element so it no longer send the same signal. The method is now calledthis.api.forward(). -
Removed
data-watch. Any element can receive a signal from anywhere else on the page without extra overhead. The biggest negative to this approach is that you have to be a little more careful to avoid naming collisions. But, the ease of use is well worth that minor trade off. -
Added Test Suite Results Report to site for easier viewing.
-
Applying passed and failed colors to individual tests for quicker scanning.
-
Updated tests to use unique signal names to avoid collisions.
Version: 1.0.0-rc2
Sept. 19, 2025
-
data-watchis applied tobitty-jselements directly instead of individual elements. The signals are send back down the tree when one is received viadata-watch -
Refactored multiple UUID() calls to single function to save a few characters.
Version: 1.0.0-rc1
Sept. 18, 2025
Initial release candidate for version 1.0.0.
No changes since v0.4.0.
Version: 0.4.0
Sept. 17, 2025
-
Flipped module arguments from
example(el, event)toexample(event, el)since that lines up better with the order of send/receive. (i.e. theeventis what gets sent fromdata-sendand theelis the element fromdata-receive -
Remove HTML output of error message. They're nice during debug but wouldn't want them showing up in prod. Could use a
debugflag but that's more overhead than I want to add. So, message just go to the console.
Version: 0.3.0
Sept. 17, 2025
Big refactor based on experience using 0.2.0.
-
Added more generic error handing where you just send a message and it outputs to the page along with the UUID of the element that had the problem. The elements have
bitty-js-errorstyle classes on them so their display can be controlled via CSS. -
Updated to use the name
data-connectinstead ofdata-module -
The
data-connectcan point to either a module or to a class in a globalbittyClasseswindow object. -
Alternate module classes are selected by passing a
|followed by the desired class name instead of usingdata-use. (e.g.data-connect="./module.js|AltClass) -
If there's an
bittyInit()function in a module it's the first thing that gets called once bitty is loaded. -
Removed
data-call. Thedata-sendattribute is used for everything. Nothing would fire from it in prior versions if there wasn't at least one element with adata-receivewith the same name. Now it calls the function once with no element if there's no associateddata-receive -
Added test suite.
-
The biggest update is changing
data-b,data-c,data-r, anddata-stodata-batch,data-call,data-receive, anddata-send, respectively. I originally use the shorter names to reduce the text length. The increased clarity of the longer names is worth the few extra characters. -
Remove expanded error messages. They were nice, but added a bunch of size without a significant improvement.
-
The other big change is removing the leading
_and$characters from function names. They were originally put in place to create a naming convention that differentiated between functions that were hit withdata-callanddata-send. In practice, that wasn't necessary. -
Removed the
data-batchattribute. While there are some use cases where it might be nice, the extra complexity, mental overhead, and maintance aren't worth it. -
Added Mutation Observer so data-* functionality works on elements that are added after initialization.
-
Added Mutation Observer to watch for removed elements to pull them out of the mix when they get gone.
-
Split the web site page up into individual template for sections. Much nicer to work with.
-
Updated example functions to always use
(el, _event)instead of(el, _)for clarity. -
Removed inert/include/ignore from the top level components then remove them. This was originally a way to tell parent components to ignore specific calls and signals from children. After using it a bit, I don't think the complexity is worth it. Better to just name functions an signals so they don't collide.
-
Isolated default signal travel to only go down the DOM. That is, if there are nested bitty-js tags, signals from the child tags don't propagate to the parent by default. (see
data-watchfor how to send signals up and to siblings) -
Added
data-watchso parents and siblings can receive signals from their children and other siblings. With this, signals can be sent up, down, and to siblings. -
Ignore events directly from
bitty-jselements (i.e. only process events from child elements). This is done to preventdata-sendattributes onbitty-jselements from firing repeatedly when things inside the element send events (e.g. clicks). -
Renamed
scriptsdirectory tomodules. -
Moved bitty source script file under
bitty-versions/bitty-v0.3.0.jsand copying to prod at the root of the site (i.e./bitty-v0.3.0.js) so examples look cleaner. -
Renamed
data-bridgetodata-connectfor clarity. -
Renamed
this.widget.bridgetothis.module.apiinbitty-js -
Added
this.api.send(key, event)to send/forward events from inside modules. -
Added Progressive Enhancement and JavaScript Data comparison examples.
-
Added/polished a bunch of other examples.
Version: 0.2.3
June 5, 2025
Lots of error handling work in this one.
-
Moved UUID generation for the
bitty-jsand alldata-*reactive elements to the first thing inconnectedCallback()to aid in error messaging. -
Made
connectedCallback()andasyncfunction to throw loading the widget module into its own funcitoun -
Created an
#errorsprivate var to store error messages and help by ID. - Added the first few error messages
-
Added
this.error()for outputting errors. It takes two optional arguments: an ID and an Element. The ID maps to the IDs in#errors. They're used to add detail and help message to the error output.The ID defaults to
0which is an unclassified error type. The message for that ID includes a note to the developer to use an ID to classify the error. I consider it a bug if an appropriate ID doesn't exist and request an issue be open to fix it.The
this.error()method dumps thebitty-jselemnet after the message.If an element was passed to
this.error()it's dumped out as well.The error message end up being pretty long. The end up adding a bunch of lines to the source file. That's an explicit decision aimed at making bitty easier to work with.
-
Added top level
debugfunction that uses adebugsearch query param from thewindow.locationto see if it should output.Only thing I don't like about it is that it shows the function's line number instead of the line number from where it was called. Something to look into.
-
The
debugfunction takes an optional element. It dumps it to the console if one comes in. -
Renamed
data-wirestodata-bridge. Fits better and maps nicer to the.bridgecoming back in from the support class. - Set up to load the default class exported from a widget module if no other class is defined (which happens with 'data-widget')
- Moved all examples to use a default class export instead of a named class
-
Added a
data-widgetattribute to thebitty-jselements to allow using multiple classes from inside a single supporting .js module file. -
bitty-component-errorandbitty-element-errorclasses are added to the class list of elements where errors occur.
Version: 0.2.2
June 4, 2025
Added UUIDs for pending error handling. Shuffeld a bunch of stuff around to make the examples look nicer.
-
Added uuids as
data-uuidattrs to all elements with relateddata-*attributes. Added them to thebitty-jselements too. I was originally thinking I'd add the UUIDs on the elements internally (i.e.el.uuidinstead ofel.dataset.uuid).I decided on the attribute approach because it offers two benefits: 1. You can see the IDs in the Element tree view of developer consoles, and 2. You can address them with CSS to update styles based on the UUID. Both of those thing will go to supporting better error messages and bug hunting.
- Mostly content updates largely focused on detailing the opening counter example.
- Added CONTRIBUTING file.
- Added watcher script to build site when files change.
-
Refined the initial counter example to remove the text and change the
private variable to
this.numto make the examples look nicer. - Moved the Examples section directly below the initial basic functionality overview section.
- Added reminders all over the place to edit the template and instead of the output for HTML page (which would be overwritten. ask me how I know).
-
Started adding
prettier-ignorecomments to code snippets to prevent the display output from being mangled. -
Started stripping
prettier-ignorecomments from the HTML output so it doesn't show in the example - Same goes for
// deno-fmt-ignore-filein .js files - Added script to maintain the open open/closed states of the section details elements across page loads. (Having them close every time I made a change was maddening)
-
Moved all the example
.jsfiles into the site root. Not a fan of that in general, but it makes the examples look better since the path is shorter.
Version: 0.2.1
June 3, 2025
Some more wiring and some support tools for making the demo/docs site.
- Made a Hello, World example that shows basic features. (Compared to the single button press from the prior first example.)
- Showing Hello, World code as part of the example.
- Load templates automatically.
- Throttling via
.requestAnimationFrame(). -
Renamed
data-ftodata-c(i.e. "call") for clarity. -
Renamed
data-prepattribute onbitty-jstag todata-call(i.e. "call") for clarity. -
Renamed
data-initattribute onbitty-jstag todata-sendso it matchesdata-smore closely. - Made basic site builder for landing page.
-
Moved everything into
detailselements for the landing page.
Version: 0.2.0
June 3, 2025
Setting up a bunch of the basic wiring.
-
Rewrite to provide direct access to receiving elements. They are fully
accessible in the send/receive functions. (As compared to the 0.1.0
approach which required explicitly defining what would happen via an
update (e.g. update
.innerHTMLor.value). -
Renamed
data-wrapperand the targetWrapperclass todata-wiresandWires. (bitty.jsis the wrapper. TheWiresclass is how things are hooked up.). -
Added
data-callattribute parsing tobitty-jstag. It runs functions likedata-cbut does so prior to adding the event listeners to the element. -
Added
data-batchattribute processing tobitty-jstags. It operates likedata-bbut fires before event listeners are added. -
Added
data-ignoreattribute to allow components to avoid calls to the named functions. (Send signals bubble up to parents of nested components by default. This provides a way to ignore them). -
The
bitty-jselement looks for an.init()method in theWiresclass. If it finds one it calls it during the initialization process. - Passing both the element and the triggering event to the send/receive functions.
-
Moved to using
data-bexplicitly to separate block calls from individual function calls. - Order of operations is: function calls, batch calls, single send calls.
- Temporarily removed preflight check until global functionality is defined.
-
Created example of loading a template via the
.init()call back to theWiresclass. - Created example with nested components.
- Created example with parent of child components pulling data from the children to do a calculation.
- Created example showing parent ignoring send signals from children.
- Created example showing on components loading a child component via a template that becomes fully reactive.
Version: 0.1.0
June 2, 2025
Getting the project started.
-
Initial prototype.
-
<bitty-js>;wraps elements to provide them with reactive capabilities. -
Basic
data-c,data-s, anddata-rin place to call functions, send, and receive updates, respectively. -
Functionality is loaded using
data-wrapperto point to a module to load. The module must export aWrapperclass that gets loaded and used to provide functions and send/receive callbacks. -
Uses string prefixes to make determinations about how to handle data through the send/receive channels (e.g.
htmlSOMETHINGupdates.innerHTMLof an element whilevalueSOMETHINGupdates the.value). -
Defined convention for functions.
data-cmaps to functions in theWrapperclass that start with a_(underscore). Thedata-sanddata-rattributes map to functions in theWrapperclass that start with a$(dollar sign). -
Decided against using
data-c data-s and data-ron thebitty.jstags. That would involved a lot of extra overhead in parsing to differentiate between the top level element and the content it wraps. Usingdata-sendinstead as a replacement fordata-c. Others, TBD. -
Set up
data-c="batchSOMETHIGN"functionality to send a single single that gets turned into multiple signals in theWrapper. -
Defined convention of using
.batchesto look for batches. It must be a hash where the keys match the incoming request and the value is an array of functions to run. -
Defined
.bridgeto allowWrapperfunctions to access the parentbitty-jselement. -
Scoped event listeners to the
bitty-jselements. -
Set up
data-listenersattribute onbitty-jstags to override the default listeners (which areinputandclick). -
Created example that stores its own state.
-
Created example that updates an element with the same content it sent (i.e. verified feedback can be avoided).
-
Created example using
data-sendto load initial values. -
Created example that sends multiple signals.
-
Created example with multiple elements receiving the same signal.
-
Created example showing how to update global CSS variables/properties.
-
Created example showing custom event listeners.
-
Created example showing how to update CSS variables/properties scoped to the content of individual
bitty-jstags. -
Examples use parent page's CSS for styling. It confirms I'm happy with the choice to use the light DOM instead of the shadow DOM.
-
Set up initial preflight check to ensure functions are in place.
Roadmap
-
TODO: Add more tests for bittyCatch()
-
TODO: Allow sending forward without having to pass a null event. That is, if there's only one argument, it's treated as the signal with a null event. So,
this.api.forward("NAME")is equivalent tothis.api.forward(null, "NAME") -
TODO: Added
data-salias fordata-sendanddata-rattribute fordata-receive -
TODO: Added
makeTXTwhich returns a text value from a template after running substitutions over it. -
TODO: Investigate: Added a
disconnectedCallback()to clean up anything that can be removed when a component is removed. -
TODO: Added
await:signaltodata-sendandthis.api.forward(event, "await:signal")to await async methods. -
TODO: Set up the
bittytag to listen for signals withdata-receiveto allow for things like completely switching out the contents of the component without having to rely on a child element calling.parentNode.
Out of Scope
These items are out of scope for bitty:
-
Triggering signals from events on the
bittyelement itself. (e.g.clickevents). The purpose of the element is as a wrapper that provides interactivity to its child elements. Not to be a click target itself. -
Including the History API in bitty's
this.api. -
Including a
s = new State()type object to maintain state. That could be set up if folks want to do it in their classes. It won't be included in bitty directly. Thedata-sendanddata-receiveattributes can send signals between components already.
History
Reference notes about the evolution of the project.
-
Any earlier prototype limited signals so they stopped at the component by default with a forwarding mechanism that allowed signals to be seen outside. That added complexity to the overall code and the mental model of working with the components themselves.
The approach is now to send signals all the way to the document root and for each component to have it's listeners attached to the document root. That means that if two components try to use the same signal name for different purposes, they'll collide.
Bitty's goal is to make things easier to build. Not to build complex systems. In that line, if a collision occurs the solution is to rename one of the signals. That's much lower overhead than dealing with limiting and forwarding mechanisms.
Test Suite
bittyInit is called automatically
Test Code
ID: 0005-bitty-init-is-called
FAILED
Test: Listeners added prior to bittyInit() call
Test Code
ID: 0007-listeneres-ready
FAILED
Basic Send and Receive
Test Code
ID: 0010-basic-send-receive
FAILED
Test Trigger
Nested Element Sending and Receiveing
Test Code
ID: 0015-nested-send-and-receive
FAILED
Test: bitty-5-0 data-send attribute
Test Code
ID: 0020-send-from-bitty-js
FAILED
Send Multiple Singnals from a Single Element
Test Code
ID: 0030-send-multiple-signals
FAILED
FAILED
FAILED
Test Trigger
Test: Newline can separate as well as space
Test Code
ID: 0035-check-newline-split
FAILED
FAILED
FAILED
Test Trigger
Multiple Receivers for a Single Sender
Test Code
ID: 0040-multiple-receivers
Test Trigger
FAILED
FAILED
FAILED
Access data-* Attributes from Sending Elements
Test Code
ID: 0050-accessing-data-from-sending-element
Test Trigger
FAILED
Access data-* Attributes from Receiving Elements
Test Code
ID: 0060-access-data-from-receiving-element
Test Trigger
FAILED
Sending Many Signals to Many Receivers
Test Code
ID: 0070-many-sends-to-many-receivers
Test Trigger
FAILED
FAILED
FAILED
Forward an Event Inside a Module
Test Code
ID: 0075-forward-inside-module
Test Trigger
FAILED
Storing State
Test Code
ID: 0080-storing-state
Test Trigger
FAILED
Sending and Receiving from the Same Element
Test Code
ID: 0090-updating-self-loopback-signal
FAILED
Get Event Type
Test Code
ID: 0100-get-event-type
Test Trigger
FAILED
Verify UUIDs are Created on Sending Elements
Test Code
ID: 0110-verify-uuids-exist-on-senders
FAILED
Verify UUIDs are Created on Receiving Elements
Test Code
ID: 0120-verify-uuids-exist-on-receivers
FAILED
Verify UUIDs Exist On All Elements
Test Code
ID: 0125-uuids-exist-on-all-elements
FAILED
Verify UUIDs Are Added To Events
Test Code
ID: 0127-uuids-exist-on-events
FAILED
Existing data-uuid Attributes Aren't Overwritten
Test Code
ID: 0128-uuids-are-not-overwritten
FAILED
FAILED
Ensure New Elements Get a data-uuid if They Have data-send/receive
Test Code
ID: 0130-create-an-element
FAILED
Ensure Elements Made from Templates Get UUIDs
Test Code
ID: 0140-ensure-template-elements-get-uuids
FAILED
const template = document.;
template. =
`<div><div><button class="test" data-send="testStub">FAILED</button></div></div>`;
Verify the bittyInit() Function Explicitly
Test Code
ID: 0160-init-function-works
FAILED
Use data-send To Call a Function When There's No Element With a Corresponding Receiver
Test Code
ID: 0170-use-data-send-without-a-receiver
FAILED
Chain this.api.forward() calls
Test Code
ID: 0220-chain-forword-api-calls
Test Trigger
FAILED
FAILED
FAILED
FAILED
// Ensure the `data-send` value of the
// event generating element doesn't
// get changed
Forward Multiple Signals
Test Code
ID: 0230-forward-multiple-signals
FAILED
FAILED
FAILED
FAILED
Call bittyInit() with await if it's async
Test Code
ID: 0250-async-bitty-init
FAILED
Use this.api.querySelector()
Test Code
ID: 0260-use-api-query-selector
FAILED
Documnet query selector
Test Code
ID: 0270-use-document-query-selector
FAILED
Forward a Signal Without an Event
Test Code
ID: 0280-forward-without-event
FAILED
Check init Order
Test Code
ID: 0290-check-init-order
FAILED
Load New Node Receivers
Test Code
ID: 0300-load-new-nodes
FAILED
Load Default window.BittyClass from Page (Manual Test)
Test Code
ID: 0330-load-default-page-class
FAILED
// This test comes from `window.BittyClass`
// on the parent HTML page.
Load Specific Class from window.TestClass0340 (Manual Test)
Test Code
ID: 0340-load-directly-from-page
FAILED
// This test comes from `window.TestClass0340`
// on the parent HTML page.
Change Event Listeners
Test Code
ID: 0350-change-event-listeners
FAILED
Nested bitty data-send does not bubble
Test Code
ID: 0360-nested-send-does-not-bubble
PASSED
Parent
Child
bitty element data-send uses bittysend event
Test Code
ID: 0370-bittysend-event
FAILED
Forward bitty tag data-send event
Test Code
ID: 0380-forward-bitty-tag-send
FAILED
Test: getJSON(url) - Success
Test Code
ID: 0390-get-json
FAILED
Test: getJSON(url) - Fetch Error
Test Code
ID: 0393-get-json-fetch-error
FAILED
Test: getJSON(url) - Parsing Error
Test Code
ID: 0394-get-json-parse-error
FAILED
Test: getJSON(url, subs) - Success
Test Code
ID: 0395-get-json-with-subs
FAILED
Test: getJSON(url, sub, options) - Success
Test Code
ID: 0397-get-json-with-options
FAILED
<!--
<details>
<summary>NOTE</summary>
<p>NOTE: This tests uses `https://echo.hoppscotch.io/`
to generate the response. If there's a failure
that's the first place to look to make sure
the service is operational
</p>
<p>NOTE: all the `.fetchThing()` methods use the same
underlying `fetchTxt(url, subs=[], options={})` call.
A passing test hear implies a passing test for
`options = {}` on `.fetchTxt()`, `.fetchHTML()`, etc...
</p>
</details>
-->
Test: makeFragment(template, subs)
Test Code
ID: 0400-make-elements
FAILED
Test: getFragment(url) - Success
Test Code
ID: 0410-get-html
FAILED
Test: getFragment(url) - Fetching Error
Test Code
ID: 0415-get-html-fetching-error
FAILED
Fetch with this.api.fetchHTML() Using Replacements
Test Code
ID: 0420-get-html-with-subs
FAILED
Fetch with this.api.fetchHTML() and RegEx Replacements
Test Code
ID: 0430-get-html-with-regex
FAILED
Test: getSVG(url, subs) - Success
Test Code
ID: 0440-get-svg
FAILED
Test: getSVG(url) - Fetching Error
Test Code
ID: 0445-get-svg-error
FAILED
Test match(event, el, KEY)
Test Code
ID: 0460-match-data
FAILED
FAILED
FAILED
FAILED
FAILED
Test Code
ID: 0465-match-data-click
Test Target
FAILED
Test this.page.match(event, el) without key
Test Code
ID: 0470-match-uuid
FAILED
FAILED
Allow empty space around data-send and data-receive
Test Code
ID: 0480-allow-empty-space
FAILED
Test: getTXT(url)
Test Code
ID: 0490-get-txt
FAILED
Test: getTXT(url, sub, options)
Test Code
ID: 0493-get-txt-subs
FAILED
Test: getTXT(url) Error
Test Code
ID: 0495-get-txt-fetching-error
FAILED
Test useEl(content, subs = [])
Test Code
ID: 0540-make-element
FAILED
const template = `<div class="test">FAILED</div>`;
Test useEl(content, subs = []) with blankspace
Test Code
ID: 0550-make-element-trim
FAILED
const template = `
<div class="test">FAILED</div>
`;
Test getElement(url)
Test Code
ID: 0560-get-element
FAILED
Test getElement(url, subs)
Test Code
ID: 0570-get-element-subs
FAILED
Test getElement(url) - Fetching Error
Test Code
ID: 0580-get-element-fetching-error
FAILED
Test: loadCSS
Test Code
ID: 0590-load-css
FAILED
License
MIT License
Copyright (c) 2025 Alan Smith - https://bitty.alanwsmith.com/
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice, this permission notice, and the ID "2y1pBoEREr3eWA1ubCCOXdmRCdn" shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.