Context Protocol
Context Protocol is a fully-typed implementation of the Context Protocol proposal — a standardized, platform-agnostic way for components to communicate shared state or services from any location in the DOM.
Features
- 🚀 Fully Typed: Full TypeScript support with comprehensive type safety and autocompletion.
- 🧠 Fully Tested: 100% test coverage ensuring reliability.
- 📦 Tree-shakeable: Import only what you need to keep your bundle size minimal.
- 🎯 Framework Agnostic: Works with any web framework or vanilla JavaScript.
- 🔄 Reactive: Additional subscription helpers for real-time context updates.
- 🛠️ Mixable: Easy integration with custom elements via mixin helpers.
Installation
npm install context-protocol
Basic Usage
At its core, Context Protocol provides the typing and event-driven behavior as defined in the Context Protocol proposal.
import { ContextRequestEvent, createContext } from "context-protocol"
// create a context for theme management
const themeContext = createContext<"light" | "dark">("theme")
document.dispatchEvent(
new ContextRequestEvent(themeContext, (value, unsubscribe) => {
// do stuff with the context value
}, true)
)
Use this low-level API with any framework or library that follows the proposal — or build your own tools on top of it.
Prefer a more ergonomic, batteries-included approach? This package also offers a minimal, tree-shakeable Subscription API built on top of Context Protocol, making it easy to provide and consume context out of the box.
Subscription API
Need live context updates? Use these helpers to get and set real-time context values.
import {
createContext,
setContextValue,
getContextValue
} from "context-protocol/subscriptions"
// create a context for theme management
const themeContext = createContext<"light" | "dark">("theme")
// set the context value
setContextValue(document, themeContext, "dark")
// get the context value
const theme = getContextValue(document, themeContext)
console.log(theme) // "dark"
Want to respond to changes? Use these listeners to react as context updates happen.
import {
createContext,
setContextValue,
addContextListener,
} from "context-protocol/subscriptions"
// create a context for user preferences
const userContext = createContext<{ name: string; age: number }>("user")
// set up a listener for user changes
addContextListener(document.body, userContext, (user, unsubscribe) => {
console.log(`User updated: ${user.name} (${user.age})`)
// unsubscribe when needed
if (user.age > 950) unsubscribe()
}, true)
// update user data
setContextValue(document, userContext, { name: "Noah", age: 600 })
Jump to:
Core Concepts
Context Creation
// create a context with a specific value type
const themeContext = createContext<"light" | "dark">("theme")
// the value type can be anything
const userContext = createContext<{ name: string }>("user")
Providers and Consumers
You can set a value on any target, then retreive that value at any time from the target or any of its descendants.
setContextValue(document, context, value)
getContextValue(document.body, context) // returns value
Subscriptions
You can subscribe to context changes on any target, and remove the listener when it’s no longer needed.
const callback = (value, unsubscribe) => {
// handle value changes
}
// listen now
addContextListener(element, context, callback, true)
// stop listening later
removeContextListener(element, context, callback)
Skip ahead to learn how the addContextListener
works.
Advanced Usage: Using Mixins
import { ContextConsumerMixin, ContextProviderMixin, createContext } from "context-protocol/mixins"
type Theme = "light" | "dark"
const themeContext = createContext<Theme>("light")
// create a custom element that provides context
class ThemeProvider extends ContextProviderMixin(HTMLElement) {
setTheme(theme: Theme) {
this.setContextValue(themeContext, theme)
}
}
// create a custom element that consumes context
class ThemeAwareElement extends ContextConsumerMixin(HTMLElement) {
connectedCallback() {
this.addContextListener(themeContext, (theme) => {
this.style.backgroundColor = theme === "dark" ? "#333" : "#fff"
})
}
}
API Reference
createContext
Creates a new context identifier, scoped by a unique key and associated with a value type. This key is used to share and consume values through the Context Protocol.
createContext<ValueType>(key: unknown): Context<unknown, ValueType>
Type Parameters:
- ValueType (
unknown
)
The type of the value associated with the context, ensuring type safety to providers and consumers.
Parameters:
- key (
unknown
)
A key used to identify the context — typically a string, symbol, or object.
Returns:
- context (
Context<typeof key, ValueType>
)
A branded context object used for matching providers and consumers.
getContextValue
Retrieves the current value of a given context from a consumer node. This is a one-time lookup and does not subscribe to future updates.
getContextValue<T>(
consumer: EventTarget,
context: T,
): void
Type Parameters:
- T (
unknown
)
The context key or the branded context type returned bycreateContext()
.
Parameters:
- consumer (
EventTarget
)
The element or node requesting the context. The protocol will walk up the tree to find a matching provider. - context (
T
asContext
)
The context key or the branded context type returned bycreateContext()
.
Returns:
- value (
ContextType<T> | undefined
)
The resolved value from the nearest matching provider, orundefined
if no value is found.
setContextValue
Delivers a value to a context, making it available to any matching consumers. If the consumer has subscribed to updates, its callback will be invoked immediately and again on future updates.
setContextValue<T>(
provider: EventTarget,
context: T,
value: ContextType<T>
): void
Type Parameters:
- T (
unknown
)
The context key or the branded context type returned bycreateContext()
.
Parameters:
- provider (
EventTarget
)
The element or node acting as the context provider. Listeners will be attached here to respond to context requests. - context (
T
asContext
)
The context key or the branded context type returned bycreateContext()
.
Subscription Methods
addContextListener
Registers a callback to receive context values delivered to a specific target.
addContextListener<T>(
consumer: EventTarget,
context: ExtractContext<T>,
callback: ContextCallback<ContextType<T>>,
subscribe?: boolean,
): void
Type Parameters:
- T (
unknown
)
The context key or the branded context type returned bycreateContext()
.
Parameters:
- consumer (
EventTarget
)
The element or node that should receive the context. This is typically a DOM node that wants to consume a value. - context (
T
asContext
)
The context key or the branded context type returned bycreateContext()
. - callback (
(value: T, unsubscribe?: () => void) => void
)
A function invoked with the resolved context value. If subscribe is true, the callback may be re-invoked when the context value changes. The callback receives an unsubscribe function if a subscription was made. - subscribe (
boolean
, optional)
If true, the callback will be subscribed to future updates to this context. Defaults to false.
removeContextListener
Unregisters a previously registered context listener.
removeContextListener<T>(
consumer: EventTarget,
context: T,
callback: ContextCallback<ContextType<T>>,
): void
Type Parameters:
- T (
unknown
)
The context key or the branded context type returned bycreateContext()
.
Parameters:
- consumer (
EventTarget
)
The element or node from which the listener should be removed. - context (
T
asContext
)
The context key or branded context type originally used. - callback (
(value: T, unsubscribe?: () => void) => void
)
The callback function to remove. This must match the exact reference passed to addContextListener.
Subscription Mixins
ContextConsumerMixin
A mixin that equips any EventTarget
class (like Custom Elements) with methods to consume context values.
ContextConsumerMixin<T extends EventTargetConstructor>(Target: T): T & ContextConsumerMixin.Constructor
Type Parameters:
- T (
EventTargetConstructor
)
A constructor function that returns anEventTarget
instance. Commonly used withHTMLElement
.
Returns:
- ConsumerTarget (
T & ContextConsumerMixin.Constructor
)
A class extended with consumer methods for context.
Adds the following methods:
addContextListener(context, callback, subscribe?)
Subscribes to a context value. Optionally listens for future updates.removeContextListener(context, callback)
Unsubscribes a previously registered callback.
ContextProviderMixin
A mixin that equips any EventTarget
class (like Custom Elements) with a method to provide context values to matching consumers.
ContextProviderMixin<T extends EventTargetConstructor>(Target: T): T & ContextProviderMixin.Constructor
Type Parameters:
- T (
EventTargetConstructor
)
A constructor function that returns anEventTarget
instance. Commonly used withHTMLElement
.
Returns:
- ProviderTarget (
T & ContextProviderMixin.Constructor
)
A class extended with provider methods for context.
Adds the following methods:
setContextValue(context, value)
Provides a value to the given context, delivering it to all matching consumers.
Contributing
We welcome contributions! Here's how to get started:
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature
) - Commit your changes (
git commit -m "Add amazing feature"
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
License
This project is licensed under the MIT No Attribution License.