caast
v1.3.0
Published
A TypeScript-safe React component library
Maintainers
Readme
caast
Detect clicks from anywhere in your React app. Simple, server-friendly, zero setup.
Why caast?
Tired of wrapping your app in providers just to detect clicks across components? caast lets you listen for clicks from anywhere in your React tree—even across server and client component boundaries—with zero setup.
One Listener, Multiple Casters. One component listens for clicks, many components can trigger it. Perfect for detecting user interactions from multiple places and responding with your own logic.
caast includes a built-in toggle function (on/off switching), but you're free to use the click detection however you want—the onCast callback gives you full control.
Features
✨ Server Component Friendly - Casters work as server components (no "use client" needed)
🎯 Simple API - Just two components: Listener and Caster
🚀 No Providers - Skip the Context API complexity
🔗 Cross-Boundary Communication - Works seamlessly between server and client components
🎨 Works with Any Element - Buttons, links, divs—anything can be a Caster
⚡ Zero JavaScript Overhead - Uses native browser APIs, no event listeners, optimized by default
Installation
npm install caastQuick Start
Basic Usage
"use client"; // Only needed where Listener is used
import { Listener, Caster } from "caast";
function MyComponent() {
const handleToggle = (value: boolean) => {
console.log("Toggled:", value);
// Update your state, open/close modals, etc.
};
return (
<>
{/* One Listener - must be in a client component */}
<Listener channel="sidebar" onCast={handleToggle} />
{/* Multiple Casters - can be anywhere, even server components */}
<Caster channel="sidebar">
<button>Toggle Sidebar</button>
</Caster>
<Caster channel="sidebar">
<a href="#">Or click here</a>
</Caster>
{/* Works with any element */}
<Caster channel="sidebar">
<div className="custom-trigger">Custom trigger</div>
</Caster>
</>
);
}Server + Client Components
// app/layout.tsx (Server Component)
import { Caster } from "caast";
export default function Layout() {
return (
<header>
{/* Server component - no "use client" needed! */}
<Caster channel="menu">
<button>Menu</button>
</Caster>
</header>
);
}
// app/menu.tsx (Client Component)
("use client");
import { Listener } from "caast";
export function Menu() {
const [isOpen, setIsOpen] = useState(false);
return (
<>
{/* Listener must be in client component */}
<Listener channel="menu" onCast={setIsOpen} />
{isOpen && <div>Menu content</div>}
</>
);
}Multiple Casters, One Listener
"use client";
import { Listener, Caster } from "caast";
function App() {
const handleModal = (isOpen: boolean) => {
// Handle modal state
};
return (
<>
{/* One Listener handles all Casters */}
<Listener channel="modal" onCast={handleModal} />
{/* Multiple triggers from anywhere */}
<Caster channel="modal">
<button>Open from header</button>
</Caster>
<Caster channel="modal">
<a href="#">Open from link</a>
</Caster>
<Caster channel="modal">
<div onClick={handleSomething}>Open from custom element</div>
</Caster>
</>
);
}How It Works
- Listener - Listens for clicks on a specific
channelfrom anywhere in your app - Caster - Triggers the Listener when clicked (can be anywhere in your component tree)
- Channel - A string identifier that connects Casters to their Listener
When any Caster with the same channel is clicked, it detects the click and calls your onCast callback with a boolean value. The communication happens through native browser APIs—no JavaScript event listeners, no complex state management, just pure browser magic. The Listener maintains an internal toggle state (on/off), but you can use the boolean value however you want—update your own state, trigger side effects, or ignore the toggle entirely.
Use Cases
- Click Detection - Detect clicks from multiple components across your app
- Modals & Dialogs - Open/close from multiple buttons (use the toggle or your own state)
- Sidebars & Drawers - Detect clicks from header, footer, or anywhere
- Accordions - Detect clicks from multiple triggers
- Theme Toggles - Detect theme switch clicks from various UI elements
- Any click-based interaction - Respond to clicks from anywhere, handle them your way
Rules
✅ One Listener per channel - Each channel should have exactly one Listener
✅ Multiple Casters - You can have as many Casters as you want for one Listener
✅ Listener in client component - The Listener component must be in a client component (use 'use client')
✅ Casters anywhere - Caster components work as server components by default
That's It!
No providers, no context setup, no complex state management, no JavaScript event listeners. Just Listener and Caster connected by a channel name. The communication happens through native browser APIs—simple, optimized, and works everywhere.
Made with ❤️ for React developers who value simplicity.
