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

@lookwe/lit-controllers

v1.1.5

Published

Controllers to simplify Lit lifecycle and more

Readme

lit-controllers

A collection of Lit.js reactive controllers for managing side effects, effect groups, memoization and slotted content in your Lit-based applications.

Installation

You can install the library via npm :

npm i @lookwe/lit-controllers

Usage

EffectController

The EffectController runs a callback function whenever the specified dependencies change. You can control whether the effect runs before or after the render with the strategy option.

import { html, LitElement } from 'lit';
import { state } from 'lit/decorators.js';

import { EffectController } from '@lookwe/lit-controllers';

class MyElement extends LitElement {
	@state() accessor #count = 0;

	// EffectController: Executes the effect when `count` changes
	#_effectController = new EffectController(
		this,
		([count], prevDeps) => {
			const [previousCount] = prevDeps ?? [];
			console.log('Effect triggered!');
			console.log('Current count:', count);
			console.log('Previous count:', previousCount);
		},
		() => [this.#count], // Dependencies (the `count` property)
		{ strategy: 'updated' }, // Effect will run after the render
	);

	render() {
		return html`
			<button @click="${this.#increment}">Increment</button>
			<p>Count: ${this.#count}</p>
		`;
	}

	#increment() {
		this.#count += 1;
	}
}
customElements.define('my-element', MyElement);

Playground

Parameters:

  • callback: The function called with the current and previous dependencies.
  • deps: A function that returns an array of dependencies.
  • options (optional): Set the strategy to "update" (before the render) or "updated" (after the render).

EffectGroupController

The EffectGroupController manages multiple EffectController instances, grouping them together based on shared dependencies. You can add or remove all controllers at once from the host element.

import { html, LitElement } from 'lit';
import { state } from 'lit/decorators.js';

import { effect, EffectGroupController } from '@lookwe/lit-controllers';

class MyElement extends LitElement {
	@state() accessor #count = 0;
	@state() accessor #name = 'John';

	// EffectGroupController: Executes multiple effects together
	#_effects = new EffectGroupController(
		this,
		effect(
			([count]) => {
				console.log('Effect 1 triggered!');
				console.log('Current count:', count);
			},
			() => [this.#count],
		),

		effect(
			([name]) => {
				console.log('Effect 2 triggered!');
				console.log('Current name:', name);
			},
			() => [this.#name],
		),
	);

	render() {
		return html`
			<button @click="${this.#increment}">Increment</button>
			<button @click="${this.#changeName}">Change Name</button>
			<p>Count: ${this.#count}</p>
			<p>Name: ${this.#name}</p>
		`;
	}

	#increment() {
		this.#count += 1;
	}

	#changeName() {
		this.#name = this.#name === 'John' ? 'Jane' : 'John';
	}
}
customElements.define('my-element', MyElement);

Playground

Methods :

  • removeControllers(): Removes all the EffectController instances from the host.
  • addControllers(): Adds all the EffectController instances back to the host.

MemoController

The MemoController memoizes the result of a callback function based on its dependencies. It prevents unnecessary re-evaluations when dependencies haven't changed.

import { html, LitElement } from 'lit';
import { state } from 'lit/decorators.js';

import { MemoController } from '@lookwe/lit-controllers';

class MyElement extends LitElement {
	@state() accessor #count = 0;

	// MemoController: Memoizes the result of the callback
	#memoController = new MemoController(
		this,
		([count]) => {
			console.log('Memoized value calculated!');
			return count * 2;
		},
		() => [this.#count],
	);

	render() {
		return html`
			<button @click="${this.#increment}">Increment</button>
			<p>Memoized value: ${this.#memoController.value}</p>
		`;
	}

	#increment() {
		this.#count += 1;
	}
}
customElements.define('my-element', MyElement);

Playground

Parameters:

  • callback: A function that computes the value based on the dependencies.
  • deps: A function that returns the dependencies array.

Methods:

  • value: Returns the memoized value.
  • getValue(forceCheckDeps = false): Returns the memoized value, optionally forcing a re-evaluation of the dependencies.

SlotController

The SlotController manages slotted content and updates its host element when the slotted content changes. It provides helper methods for checking and retrieving assigned slot content.

import { html, LitElement } from 'lit';

import { SlotController } from '@lookwe/lit-controllers';

class MyElement extends LitElement {
	#slotController = new SlotController(this); // Manages all slots

	render() {
		return html`
			<slot></slot>
			<slot name="named"></slot>
			<p>Default slot has content: ${this.#slotController.hasAssignedNodes() ? 'Yes' : 'No'}</p>
			<p>Named slot has content: ${this.#slotController.hasAssignedNodes('named') ? 'Yes' : 'No'}</p>
		`;
	}
}
customElements.define('my-element', MyElement);

Playground

Parameters:

  • slotNames (optional): An iterable of slot names to manage. If not provided, all slots are managed.

Methods:

  • getAssignedNodes(slotName?: string): Gets an array of assigned nodes for the specified slot.
  • getAssignedElements(slotName?: string): Gets an array of assigned elements for the specified slot.
  • hasAssignedNodes(slotName?: string): Checks if the specified slot has any assigned nodes.
  • hasAssignedElements(slotName?: string): Checks if the specified slot has any assigned elements.