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

targetj

v1.0.219

Published

TargetJS: UI Development as a Sequence.

Readme

TargetJS: UI Development as a Sequence

targetjs.io MIT LICENSE Stars npm version

TargetJS is a high-performance JavaScript UI framework with ultra-compact syntax. It replaces the "State → Render" model with a Code-Ordered Reactivity. It unifies UI, animations, APIs, event handling, and state into self-contained "Targets" that stack together like intelligent Lego pieces.

It can be used as a full-featured framework or as a lightweight library alongside other frameworks. It is also a highly performant web framework, as shown in the framework benchmark.

The Philosophy Behind TargetJS

Traditional frameworks model the UI as a function of state: change state, re-render the UI. When state changes from A to B, the UI immediately jumps to B. The framework doesn’t naturally represent the journey from A to B. But modern, rich user experiences are journeys, not jumps. They are built on sequences that unfold over time. For example:

Click → Animate button → Chain secondary animation → Fetch data → Render list → Animate items → Pause → Animate an important item

TargetJS is built for this reality. Instead of managing complex flags, your code structure mirrors these sequences directly.

It achieves this through Targets. A Target is a self-contained unit that merges data (fields) and logic (methods) into a single reactive block. Each Target has its own internal state, timing, and lifecycle, acting like a living cell within your app. By simply ordering them in your code, you create complex asynchronous workflows without async/await or .then() chains.

In addition, efficient animation is built directly into the framework using the Web Animations API, delivering CSS-level efficiency.

By adopting a compact style, TargetJS makes the journey from A to B efficient and explicit, with significantly less code than traditional frameworks.

⚡ Quick Start (30 Seconds)

1. Install

npm install targetj

2. The "Hello World" Sequence

This creates a blue box that grows, then turns red, and then logs "Hello World" in order.

import { App } from "targetj";

App({
  backgroundColor: 'blue', // Starts immediately
  width: { value: [100, 200], steps: 100 }, // Starts immediately: animate width from 100px to 200px in 100 steps with 8 ms interval per step.
  height: { value: [100, 200], steps: 100 }, // Starts immediately: animate height.
  backgroundColor$$: { value: 'red', steps: 100 }, // Wait ($$) for width/height to finish
  done$$() { console.log("Hello World!"); } // 3. Waits ($$) for the background color
}).mount("#app");

Understanding TargetJS Syntax

These symbols tell the framework when a target should run.

| Symbol | Name | Behavior | | -------- | -------- | -------------------------------------------------------------------------------------------------------------------------| | name | Standard | Runs immediately in the order it appears. | | name$ | Reactive | Runs every time the previous sibling target executes. | | name$$ | Deferred | Executes only after the entire preceding target chain including children, animations, and API calls has fully completed. | | _name | Inactive | Does not run automatically. Trigger it manually via .activateTarget(). |

Examples: Like Button → Animated Like (in 3 Steps)

Let’s see how TargetJS handles a complex interaction that would usually require 50+ lines of React/CSS. The example demonstrates how to run four asynchronous operations in a strict sequential sequence, where each step waits for the previous ones to complete.

1) Like button

One object defines a UI element without separate HTML/CSS. Static targets map directly to DOM styles/attributes. You can still use CSS if wanted.

<div id="likeButton"></div>
import { App } from "targetj";

App({
  width: 220,
  height: 60,
  lineHeight: 60,
  textAlign: "center",
  borderRadius: 10, 
  html: "♡ Like",
  // Runs immediately on mount
  scale: { value: [1.2, 1], steps: 12, interval: 12 },
  backgroundColor: { value: ["#ffe8ec", "#f5f5f5"], steps: 12, interval: 12 }
}).mount("#likeButton");

2) Adding the Interaction

We move the animation into an onClick and add a deferred heart animation.

<div id="likeButton"></div>
import { App } from "targetj";

App({
  width: 220, height: 60, lineHeight: 60, textAlign: "center",
  borderRadius: 10, backgroundColor: "#f5f5f5",
  cursor: "pointer", userSelect: "none",
  html: "♡ Like",
  onClick() {
    this.setTarget('scale', { value: [1.2, 1], steps: 8, interval: 12 });
    this.setTarget('backgroundColor', { value: [ '#ffe8ec', '#f5f5f5' ], steps: 12, interval: 12 });
  },
  heart$$: {  // Wait for the button animation to finish, THEN add and animate the heart.
    html: "♥", color: "crimson", fontSize: 20,
    fly() {
      const cx = this.getCenterX(), cy = this.getCenterY();
      this.setTarget({
        opacity: { value: [0, 1, 1, 0.8, 0.1], steps: 20 },
        scale:   { value: [0.8, 1.4, 1.1, 0.9, 0.8], steps: 20 },
        rotate:  { value: [0, 12, -8, 6, 0], steps: 20 },
        x:       { value: [cx, cx + 22, cx - 16, cx + 10, cx], steps: 30 },
        y:       { value: [cy - 8, cy - 70, cy - 90, cy - 120, cy - 150], steps: 30 }
      });
    }
  }  
}).mount("#likeButton");

3) The Full Async Workflow

We handle UI, two animations, a POST request, and a cleanup.

<div id="likeButton"></div>
import { App } from "targetj";

App({
  width: 220, height: 60, lineHeight: 60, textAlign: "center",
  borderRadius: 10, backgroundColor: "#f5f5f5", cursor: "pointer", userSelect: "none",
  role: "button", tabIndex: 0,
  html: "♡ Like",
  onClick() {
    this.setTarget('scale', { value: [1.2, 1], steps: 8, interval: 12 });
    this.setTarget('backgroundColor', { value: [ '#ffe8ec', '#f5f5f5' ], steps: 12, interval: 12 });
  },
  heart$$: {
    html: "♥", color: "crimson", fontSize: 20,
    fly() {
      const cx = this.getCenterX(), cy = this.getCenterY();
      this.setTarget({
        opacity: { value: [0, 1, 1, 0.8, 0.1], steps: 20 },
        scale:   { value: [0.8, 1.4, 1.1, 0.9, 0.8], steps: 20 },
        rotate:  { value: [0, 12, -8, 6, 0], steps: 20 },
        x:       { value: [cx, cx + 22, cx - 16, cx + 10, cx], steps: 30 },
        y:       { value: [cy - 8, cy - 70, cy - 90, cy - 120, cy - 150], steps: 30 }
      });
    }
  },
  fetch$$: { method: "POST", id: 123, url: "/api/like" }, // Wait for the heart to finish, THEN fetch
  removeHearts$$() { this.removeChildren(); }, // Wait for fetch to finish, THEN cleanup
  onKey(e) { if (e.key === "Enter") this.activateTarget("onClick"); } 
}).mount("#likeButton");

Summary

Each target has its own state and lifecycle. Targets execute automatically in the order they are written. $$ defers execution until all prior sibling targets (including their children) are fully complete. Animations, API calls, event handling, and child creation are all treated uniformly as targets. Complex asynchronous flows can be structured by organizing work into parent and child targets. In addition, targets provide built-in capabilities such as onComplete callbacks, enabledOn, looping with delays, and more. This also makes the code more compact, as it avoids using extra variables to track progress and reduces the need for loops and conditional statements.


Table of Contents

  1. 📦 Alternative Installation Via CDN
  2. 🚀 Why TargetJS?
  3. Deeer Examples:
  4. Target Methods
  5. Special Target Names
  6. How to Debug in TargetJS
  7. Documentation
  8. License
  9. Contact
  10. 💖 Support TargetJS

📦 Alternative Installation Via CDN

Add the following <script> tag to your HTML to load TargetJS from a CDN:

<script src="https://unpkg.com/targetj@latest/dist/targetjs.js"></script>

This exposes TargetJS on window, so you can initialize your app with TargetJS.App(...).

Ensure your code runs after the DOM is ready (use defer, place your script at the bottom of the <body>, or wrap it in a DOMContentLoaded listener).

<div id='redbox'></div>

<script>
    TargetJS.App({
        backgroundColor: 'red',
        width: { value: [100, 250, 100], steps: 20 },
        height: { value: [100, 250, 100], steps: 20 }
    }).mount('#redbox');
</script>

Zero-JS Declarative HTML

TargetJS can also be used as a "no-code" library. Elements with tg- attributes are discovered and activated automatically.

<div
   tg-background="red"
   tg-width="{ value: [100, 250, 100], steps: 20 }"
   tg-height="{ value: [100, 250, 100], steps: 20 }">
</div>

🚀 Why TargetJS?

  1. Zero Boilerplate Async: The $$ postfix handles the "wait" for you.
  2. Unified State: State isn't "elsewhere". It's built into every Target.
  3. Animation by Default: High-performance animations are baked into the logic.
  4. Ultra-Compact: Write 70% less code than standard frameworks.
  5. Lower Cognitive Load: Code reads from top to bottom, exactly how the user experiences the interaction.

Deeper Examples

Loading Five Users Example

In this example, we load five separate users and display five boxes, each containing a user's name and email.

  • fetch calls five APIs to retrieve details for five users.

  • child is a special target that adds a new item to the parent each time it executes. Because it ends with $ in this example, it executes every time an API call returns a result.

  • TargetJS ensures that API results are processed in the same sequence as the API calls. For example, if the user1 API result arrives before user0, child will not execute until the result for user0 has been received.

<div id="users"></div>
import { App } from "targetj";

App({
    gap: 10,
    fetch: ['https://targetjs.io/api/randomUser?id=user0',
        'https://targetjs.io/api/randomUser?id=user1',
        'https://targetjs.io/api/randomUser?id=user2',
        'https://targetjs.io/api/randomUser?id=user3',
        'https://targetjs.io/api/randomUser?id=user4'
    ],
    child$() {
        // prevTargetValue Holds the previous target’s value. For fetch targets, this is each API result in code order,
        // not the order in which responses arrive in the browser.
        const user = this.prevTargetValue;
        return {
          width: 200,
          height: 65,
          borderRadius: 10,
          boxSizing: "border-box",
          padding: 10,
          fontSize: 14,
          backgroundColor: "#f0f0f0",
          scale: { value: [0.8, 1], steps: 14, interval: 12 },
          userName$$: {
            padding: "10px 0 5px 10px",
            boxSizing: "border-box",
            fontWeight: 600,
            opacity: { value: [0, 1], steps: 50 },
            html: user.name
          },
          userEmail$$: {
            paddingLeft: 10,
            boxSizing: "border-box",
            opacity: { value: [0, 0.7], steps: 50 },
            html: user.email
          }
       };
    }
}).mount("#users");

It can also be written using a target’s cycles and interval properties/methods to fetch users at intervals instead of in a single batch. In this example, we set interval to 1000, making the API call once every second.

App({
    gap: 10,
    fetch: {
        interval: 1000,
        cycles: 4,
        value(i) { return `https://targetjs.io/api/randomUser?id=user${i}`; }
    },
    child$() {   
        return {
          // …same as the previous example…
        };
    }
}).mount("#users");

Infinite Loading and Scrolling Example

In this advanced example, we implement an infinite-scrolling application.

  • addChildren is a special target that adds multiple items to the container’s children each time it executes. The onVisibleChildrenChange event detects changes in the visible children and activates addChildren to insert new items and fill any gaps.

  • photo and userName each add a div element inside every item, serving as placeholders for the photo and user name.

  • pause$$ delays the execution of all targets that follow it by 100 ms.

  • fetch$$ retrieves the user’s details.

  • reveal$$ executes after fetch$$, revealing the user name and populating the photo with a random color.

  • wave$$ executes only after all preceding children have completed their targets, giving each user item a coordinated animation.

TargetJS employs a tree-like structure to track visible branches, optimizing scroller performance.

<div id="userList"></div>
import { App, getEvents, getScreenWidth, getScreenHeight } from "targetj";

App({
  preventDefault: true,
  width: 250,
  height() { return getScreenHeight(); },
  x() { return (getScreenWidth() - this.getWidth()) / 2; },
  containerOverflowMode: "always",
  addChildren() {
    return Array.from({ length: 10 }, (_, i) => ({
      height: 56,
      width() { return this.parent.getWidth(); },
      bottomMargin: 8,
      borderRadius: 12,
      backgroundColor: "white",
      validateVisibilityInParent: true,
      boxShadow: "0 8px 20px rgba(0,0,0,0.08)",
      photo: {
        x: 10, y: 10, width: 34, height: 34,
        borderRadius: "50%",
        backgroundColor: "#ddd"
      },
      userName: {
        x: 60, y: 10, width: 180, height: 30,
        overflow: "hidden",
        borderRadius: 5,
        backgroundColor: "#ddd"
      },
      pause$$: { interval: 100 },
      fetch$$: "https://targetjs.io/api/randomUser",
      reveal$$() {
        const userName = this.getChild("userName");
        userName.setTarget("html", this.val("fetch$$").name);
        userName.setTarget("backgroundColor", { value: "white", steps: 20 });
        this.getChild("photo").setTarget("backgroundColor", { value: "#" + Math.random().toString(16).slice(-6), steps: 20 });
      },
    }));
  },
  wave$$: {
    interval: 30,
    cycles() { return this.visibleChildren.length - 1; },
    value(i) {
      const child = this.visibleChildren[i];
      child.setTarget("scale", { value: [1, 1.06, 1], steps: 18 });
      child.setTarget("opacity", { value: [1, 0.92, 1], steps: 18 });
    }
  },
  onScroll() {
    this.setTarget("scrollTop", Math.max(0, this.getScrollTop() + getEvents().deltaY()));
  },
  onVisibleChildrenChange() {
    const visibleCount = this.visibleChildren.length;
    if (getEvents().dir() !== "up" && visibleCount * 64 < this.getHeight()) {
      this.activateTarget("addChildren");
    }
  }
}).mount("#userList");

Technical Reference

Target Methods

Every target can be an object with these optional controls:

  1. value The data or function that determines the target's state.

  2. steps Turns a value change into an animation (e.g., steps: 20).

  3. interval The delay (ms) between steps or executions.

  4. cycles How many times to repeat the target.

  5. onComplete Callback when this target (and its children) finishes.

  6. enabledOn Determines whether the target is enabled for execution.

  7. loop Managed the repetition of target execution. Similar to cycles but uses boolean instead.

  8. easing A string that defines a predefined easing function that controls how the actual value is updated in relation to the steps.

  9. onValueChange This callback is triggered when value emits a new value.

Special Target Names

TargetJS maps directly to the DOM for zero-friction styling. For example:

  • Styles: width, height, opacity, x, y, rotate, scale, backgroundColor.
  • Structure: html, children, element, domHolder.
  • Events: onClick, onScroll, onKey, onVisibleChildrenChange, onResize.

How to Debug in TargetJS

TargetJS provides built-in debugging tools:

TargetJS.tApp.stop(); // Stop the application.
TargetJS.tApp.start(); // Restart the application
TargetJS.tApp.throttle = 0; // Slow down execution (milliseconds between cycles)
TargetJS.tApp.debugLevel = 1; // Log cycle execution
  • Use t() in the browser console to find an object by its oid.
  • Use t(oid).bug() to inspect all the vital properties.
  • Use t(oid).logTree() to inspect the UI structure.

Documentation

Explore the potential of TargetJS and dive into our interactive documentation at www.targetjs.io.

License

Distributed under the MIT License. See LICENSE for more information.

Contact

Ahmad Wasfi - [email protected]

💖 Support TargetJS

If you would like to show some appreciation:

  • ⭐ Star this repo on GitHub to show your support!
  • 🐛 Report issues & suggest features.
  • 📢 Share TargetJS with your network.