Compatibility
WebShorts is designed to work with any React framework. Learn about specific setup requirements for different frameworks.
⚠️
Next.js App Router
⚠️ CRITICAL: Client Wrappers Required
If you are using Next.js App Router (the /app
directory), you MUST use client wrappers for both the WebShortsProvider and ShortcutListener components. This is not optional - you WILL encounter SSR/hydration issues without them.
Setup Instructions
1. Create the Client Provider Wrapper
// components/ClientWebShortsProvider.jsx
'use client';
import { useEffect, useState } from 'react';
import { WebShortsProvider, WebShortsDialog } from '@chrisnski/webshorts';
import { usePathname } from 'next/navigation';
import { Toaster } from 'sonner';
export default function ClientWebShortsProvider({ children, config, className }) {
const [mounted, setMounted] = useState(false);
const pathname = usePathname();
useEffect(() => {
setMounted(true);
}, []);
if (!mounted) {
// Return children without the provider during SSR
return children;
}
return (
<WebShortsProvider config={config} currentPage={pathname} className={className}>
{children}
<WebShortsDialog />
<Toaster position='bottom-right' richColors />
</WebShortsProvider>
);
}
2. Create the App Wrapper
// components/WebShortsProviderWrapper.jsx
'use client';
import ClientWebShortsProvider from './ClientWebShortsProvider';
import webshortsConfig from '../webshorts.config';
export default function WebShortsProviderWrapper({ children, className }) {
return (
<ClientWebShortsProvider config={webshortsConfig} className={className}>
{children}
</ClientWebShortsProvider>
);
}
3. Use in Root Layout
// app/layout.js (Server Component)
export const metadata = {
title: 'My App',
description: 'My app description'
};
import WebShortsProviderWrapper from '../components/WebShortsProviderWrapper';
export default function RootLayout({ children }) {
return (
<html>
<body>
<WebShortsProviderWrapper>
{children}
</WebShortsProviderWrapper>
</body>
</html>
);
}
4. Create Client Wrapper for ShortcutListener (REQUIRED)
// components/ClientShortcutListener.jsx
'use client';
import { useEffect, useState } from 'react';
import { ShortcutListener } from '@chrisnski/webshorts';
export default function ClientShortcutListener({ children, keys, action, shortName, description }) {
const [mounted, setMounted] = useState(false);
useEffect(() => {
setMounted(true);
}, []);
if (!mounted) {
// Return the children without the ShortcutListener wrapper during SSR
return children;
}
return (
<ShortcutListener
keys={keys}
action={action}
shortName={shortName}
description={description}
>
{children}
</ShortcutListener>
);
}
5. Usage Example
// Instead of using ShortcutListener directly:
<ShortcutListener keys="CTRL + S" action={handleSave} shortName="Save" description="Save content">
<div>Press CTRL + S to save</div>
</ShortcutListener>
// Use the client wrapper:
import ClientShortcutListener from '@/components/ClientShortcutListener';
<ClientShortcutListener keys="CTRL + S" action={handleSave} shortName="Save" description="Save content">
<div>Press CTRL + S to save</div>
</ClientShortcutListener>
Why Both Wrappers Are Required
- • Server Components - Next.js App Router uses server components by default
- • Context Providers - WebShortsProvider is a client-side context provider
- • Shortcut Listeners - ShortcutListener components need client-side mounting
- • SSR/Hydration Race - Both components will fail in production without wrappers
- • Guaranteed Issues - This is not optional - you WILL encounter problems without these wrappers
Note: This pattern is required for all context/hook-based libraries in Next.js App Router. See the Next.js docs for more details.
Other React Frameworks
WebShorts works seamlessly with other React frameworks without special configuration.
Create React App
// App.jsx
import { WebShortsProvider, WebShortsDialog } from '@chrisnski/webshorts';
import shortcutsConfig from './webshorts.config.js';
function App() {
return (
<WebShortsProvider config={shortcutsConfig} currentPage={pathname}>
<div className='App'>
<Header />
<Main />
<Footer />
</div>
<WebShortsDialog />
</WebShortsProvider>
);
}
Vite
// main.jsx
import { WebShortsProvider, WebShortsDialog } from '@chrisnski/webshorts';
import shortcutsConfig from './webshorts.config.js';
function App() {
return (
<WebShortsProvider config={shortcutsConfig} currentPage={pathname}>
<div className='App'>
<Header />
<Main />
<Footer />
</div>
<WebShortsDialog />
</WebShortsProvider>
);
}
Remix
// app/root.jsx
import { WebShortsProvider, WebShortsDialog } from '@chrisnski/webshorts';
import shortcutsConfig from './webshorts.config.js';
export default function App() {
return (
<html>
<head>
<Meta />
<Links />
</head>
<body>
<WebShortsProvider config={shortcutsConfig} currentPage={pathname}>
<Outlet />
<WebShortsDialog />
</WebShortsProvider>
<ScrollRestoration />
<Scripts />
</body>
</html>
);
}
Next.js Pages Router
// pages/_app.js
import { WebShortsProvider, WebShortsDialog } from '@chrisnski/webshorts';
import shortcutsConfig from './webshorts.config.js';
export default function App({ Component, pageProps }) {
return (
<WebShortsProvider config={shortcutsConfig} currentPage={pathname}>
<Component {...pageProps} />
<WebShortsDialog />
</WebShortsProvider>
);
}
Browser Compatibility
WebShorts is compatible with all modern browsers that support React.
Supported Browsers
- • Chrome 90+
- • Firefox 88+
- • Safari 14+
- • Edge 90+
Required Features
- • ES6+ support
- • React 16.8+ (hooks support)
- • Modern DOM APIs
- • Keyboard event handling
React Version Requirements
Minimum Requirements
- • React 16.8+ - Required for hooks support
- • React DOM 16.8+ - Required for DOM manipulation
- • Modern JavaScript - ES6+ features required
Recommended Versions
- • React 18+ - Latest features and performance improvements
- • React DOM 18+ - Concurrent features support
- • Node.js 16+ - For development and build tools
Common Issues & Solutions
"Module not found" errors
Make sure you've installed all peer dependencies:
npm install @radix-ui/react-dialog sonner react react-dom
Toasts not showing
Ensure Sonner is properly configured in your app:
import { Toaster } from 'sonner';
function App() {
return (
<>
<YourApp />
<Toaster />
</>
);
}
Shortcuts not working
- • Check that the WebShortsProvider wraps your entire app
- • Verify key combinations are valid (e.g., "CTRL + S" not "Ctrl + S")
- • Enable debug mode to see registration and execution feedback
- • Ensure no other libraries are intercepting keyboard events