Examples/Scoped & Nested Providers

Scoped & Nested Providers

Control feedback capture at a granular level with scoped providers and nested theming. Perfect for complex applications with different feedback requirements per section.

Try It

Right-click elements in different sections to see how scoped providers work. Notice the different highlight colors and behavior:

Global Provider (Blue highlights + Blue pointer)

This area uses the global provider with default blue highlights and blue pointer. Right-click to see the blue highlight color.

Click me too!
Nested Provider (Rose theme + Rose pointer)

This section has nested providers with custom rose-colored highlights AND rose pointer. Right-click to see the rose/pink colors and custom menu items!

Another Nested Provider (Emerald theme + Emerald pointer)

Each section can have completely different theming, menu options, and pointer colors. This one uses emerald/cyan colors.

Cyan Element
Custom Styled Menu (Glassmorphism)

This section demonstrates a fully custom-styled context menu with glassmorphism effect, custom border radius, and emoji icons. Right-click to see the custom menu design!

Orange Element
Disabled Provider (No feedback, No custom pointer)

Both feedback AND custom pointer are disabled in this section. Right-click shows the native browser menu, and you see the default cursor.

Note: Each section above has its own AnyclickProvider AND PointerProvider, demonstrating different highlight colors, menu items, pointer themes, custom menu styling, and disabled states.

Use Cases

  • Different feedback configurations per page section
  • Custom theming for specific components (colors, styles)
  • Disable feedback in sensitive areas (forms, payments)
  • Separate adapters for different feedback destinations
  • Role-based feedback with different menu items per section

Implementation

1. Basic Scoped Provider

Use the scoped prop to limit feedback capture to a specific section:

components/Dashboard.tsx
'use client';
import { AnyclickProvider } from '@ewjdev/anyclick-react';
export function Dashboard({ children }) {
return (
<AnyclickProvider
adapter={dashboardAdapter}
scoped // Only captures events within this provider's children
menuItems={dashboardMenuItems}
>
{children}
</AnyclickProvider>
);
}

2. Nested Theming

Child providers inherit and can override parent themes:

app/layout.tsx
'use client';
import { AnyclickProvider } from '@ewjdev/anyclick-react';
export function Providers({ children }) {
return (
// Root provider with blue highlights
<AnyclickProvider
adapter={adapter}
theme={{
highlightConfig: {
colors: {
targetColor: '#3b82f6', // Blue
containerColor: '#8b5cf6', // Purple
}
}
}}
>
<Header />
<main>{children}</main>
{/* Nested provider with custom rose theme */}
<AnyclickProvider
scoped
theme={{
highlightConfig: {
colors: {
targetColor: '#f43f5e', // Rose
containerColor: '#ec4899', // Pink
}
}
}}
>
<SpecialSection />
</AnyclickProvider>
<Footer />
</AnyclickProvider>
);
}

3. Scoped Pointer Theming

To have different pointer (cursor) themes per section, wrap with both AnyclickProvider and PointerProvider:

components/RoseSection.tsx
'use client';
import { AnyclickProvider } from '@ewjdev/anyclick-react';
import { PointerProvider } from '@ewjdev/anyclick-pointer';
import { MousePointer2 } from 'lucide-react';
export function RoseSection({ children }) {
return (
<AnyclickProvider
scoped
theme={{
highlightConfig: {
colors: {
targetColor: '#f43f5e', // Rose highlights
containerColor: '#ec4899',
}
}
}}
>
<PointerProvider
theme={{
colors: {
pointerColor: '#f43f5e', // Rose pointer
circleColor: 'rgba(244, 63, 94, 0.4)',
},
pointerIcon: (
<MousePointer2 size={24} fill="rgba(244, 63, 94, 0.3)" stroke="#f43f5e" />
),
}}
config={{ visibility: 'always', hideDefaultCursor: true }}
>
{children}
</PointerProvider>
</AnyclickProvider>
);
}

4. Disabling Feedback & Pointer

Disable both feedback and custom pointer for sensitive areas:

components/PaymentForm.tsx
'use client';
import { AnyclickProvider } from '@ewjdev/anyclick-react';
import { PointerProvider } from '@ewjdev/anyclick-pointer';
export function PaymentForm({ children }) {
return (
// Disable feedback
<AnyclickProvider scoped theme={{ disabled: true }}>
{/* Disable custom pointer, show default cursor */}
<PointerProvider config={{ visibility: 'never', hideDefaultCursor: false }}>
<form>
<input type="text" placeholder="Card Number" />
<input type="text" placeholder="CVV" />
<button type="submit">Pay Now</button>
</form>
</PointerProvider>
</AnyclickProvider>
);
}

5. Different Adapters Per Section

Route feedback to different destinations based on the section:

app/layout.tsx
'use client';
import { AnyclickProvider } from '@ewjdev/anyclick-react';
import { createHttpAdapter } from '@ewjdev/anyclick-github';
// Main app feedback goes to GitHub
const githubAdapter = createHttpAdapter({
endpoint: '/api/feedback/github',
});
// Dashboard feedback goes to internal tool
const internalAdapter = createHttpAdapter({
endpoint: '/api/feedback/internal',
});
export function Providers({ children }) {
return (
<AnyclickProvider adapter={githubAdapter}>
<Header />
{/* Dashboard uses different adapter */}
<AnyclickProvider
adapter={internalAdapter}
scoped
menuItems={internalMenuItems}
>
<Dashboard />
</AnyclickProvider>
<Footer />
</AnyclickProvider>
);
}

Theme Configuration

The AnyclickTheme interface:

interface AnyclickTheme {
// Custom styles for the context menu
menuStyle?: CSSProperties;
// Custom class name for the context menu
menuClassName?: string;
// Highlight configuration
highlightConfig?: {
enabled?: boolean;
colors?: {
targetColor?: string;
containerColor?: string;
targetShadowOpacity?: number;
containerShadowOpacity?: number;
};
containerSelectors?: string[];
};
// Screenshot configuration
screenshotConfig?: ScreenshotConfig;
// Disable anyclick in this subtree
disabled?: boolean;
}

useAnyclick Hook

Access the current provider context, including the merged theme:

import { useAnyclick } from '@ewjdev/anyclick-react';
function MyComponent() {
const {
isEnabled, // Whether feedback is enabled
isSubmitting, // Whether submission is in progress
theme, // Merged theme (includes parent themes)
scoped, // Whether this provider is scoped
providerId, // Unique ID for this provider
openMenu, // Open menu programmatically
closeMenu, // Close menu
submitFeedback, // Submit feedback programmatically
} = useAnyclick();
return (
<div>
<p>Feedback enabled: {isEnabled ? 'Yes' : 'No'}</p>
<p>Current highlight color: {theme.highlightConfig?.colors?.targetColor}</p>
</div>
);
}

Event Handling

When nested providers exist, events bubble from the nearest provider to the outermost. The nearest non-disabled provider handles the event:

<AnyclickProvider adapter={a1}>      ← Handles if inner is disabled
  <AnyclickProvider scoped adapter={a2}>  ← Handles first (nearest)
    <Button />  ← Right-click here
  </AnyclickProvider>
</AnyclickProvider>

Explore More

Learn about other advanced features like custom pointers and sensitive data masking.