Handling Third-Party Components in Next.js: Avoiding Common Mistakes
When building with Next.js, dealing with third-party components can sometimes cause issues, especially if they aren't correctly configured for client-side rendering. A common mistake developers make is incorrectly using third-party components that rely on React hooks or state management without marking them as client components. Let’s take a deeper look into this issue and learn how to fix it with an intuitive solution.
The Problem: Third-Party Components Without use client
In Next.js, components are classified as either server or client components. Server components don't have access to browser-specific features like state, effects, or event listeners, while client components can use these React hooks.
Many third-party libraries (like carousels or modals) internally use React hooks like useState
or useEffect
. However, these libraries might not explicitly mark their components as client components in the source code. As a result, if you try to use these components directly, you may run into errors, such as trying to use state or hooks in a server environment.
Here’s a typical scenario of what not to do:
import { Carousel } from 'some-carousel-library';
const MyPage = () => {
return (
<div>
<h1>My Image Gallery</h1>
<Carousel>
<img src="/image1.jpg" alt="Image 1" />
<img src="/image2.jpg" alt="Image 2" />
</Carousel>
</div>
);
};
export default MyPage;
In this case, you may encounter an error like:
Error: Hooks can only be called inside the body of a function component (useEffect/useState) — but this is a server component.
The Solution: Create a Client-Side Wrapper
To solve this issue, you need to wrap the third-party component in a custom component that explicitly marks it as a client component by using the "use client"
directive. This tells Next.js to treat this wrapper as a client component, allowing you to safely use React hooks and state.
Here’s how to do it:
Step-by-Step: Wrapping Third-Party Components
1. Create a Client Wrapper Component
Start by creating a new component that will serve as a wrapper for the third-party library component. The key here is to add the "use client"
directive at the top of this wrapper file.
// CarouselWrapper.js
"use client"; // This ensures the component runs on the client side
import { Carousel } from 'some-carousel-library';
const CarouselWrapper = () => {
return (
<Carousel>
<img src="/image1.jpg" alt="Image 1" />
<img src="/image2.jpg" alt="Image 2" />
<img src="/image3.jpg" alt="Image 3" />
</Carousel>
);
};
export default CarouselWrapper;
2. Use the Wrapper Component in Your Page
Once you have created the wrapper, you can now safely import and use it in any page or component where you need the carousel.
import CarouselWrapper from './CarouselWrapper';
const MyPage = () => {
return (
<div>
<h1>My Image Gallery</h1>
<CarouselWrapper />
</div>
);
};
export default MyPage;
Now, the carousel component works without causing errors because we have explicitly told Next.js to treat CarouselWrapper
as a client component. This ensures that the third-party library (which uses hooks or state) only runs on the client side.
Why Does This Happen?
When you use a third-party component that isn't properly marked for client-side usage, Next.js assumes it's a server component by default. Since server components can't handle state or effects, any attempt to use hooks in them throws an error. By wrapping it in a component marked with "use client"
, you ensure that the component is only executed on the client side, where hooks and state are supported.
Other Common Use Cases for Wrapping Third-Party Components
This pattern can be applied to a wide range of third-party libraries that rely on client-side features, including:
Modals that manage their own visibility state
Charts that use hooks like
useEffect
for renderingInteractive Maps (e.g., Google Maps or Leaflet) that need access to
window
ordocument
objects
In each case, the same solution applies: create a wrapper component with "use client"
to ensure smooth client-side behavior.
Example: Wrapping a Third-Party Modal Component
Let’s walk through another example where we wrap a third-party modal component that uses state for toggling visibility:
// ModalWrapper.js
"use client";
import { Modal } from 'some-modal-library';
import { useState } from 'react';
const ModalWrapper = () => {
const [isOpen, setIsOpen] = useState(false);
return (
<div>
<button onClick={() => setIsOpen(true)}>Open Modal</button>
{isOpen && (
<Modal onClose={() => setIsOpen(false)}>
<p>This is a modal window</p>
</Modal>
)}
</div>
);
};
export default ModalWrapper;
Now, you can safely use this modal on a Next.js page without encountering server-side rendering issues:
import ModalWrapper from './ModalWrapper';
const MyPage = () => {
return (
<div>
<h1>My Awesome Page</h1>
<ModalWrapper />
</div>
);
};
export default MyPage;
Conclusion
When using third-party components in Next.js that rely on client-side features like hooks, state, or event listeners, it's essential to properly handle them by creating a wrapper component marked with "use client"
. This simple step ensures that these components work smoothly without errors during server-side rendering.
By using this approach, you can continue to take advantage of powerful third-party libraries in your Next.js applications while maintaining the benefits of server-side rendering where appropriate.
Subscribe to my newsletter
Read articles from Rishi Bakshi directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Rishi Bakshi
Rishi Bakshi
Full Stack Developer with experience in building end-to-end encrypted chat services. Currently dedicated in improving my DSA skills to become a better problem solver and deliver more efficient, scalable solutions.