responsive breakpoints are not working
Hey @react-slick
"dependencies": { "next": "16.0.1", "react": "19.2.0", "react-dom": "19.2.0", "react-slick": "^0.31.0", "slick-carousel": "^1.8.1" }, "devDependencies": { "@tailwindcss/postcss": "^4", "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", "@types/react-slick": "^0.23.13", "eslint": "^9", "eslint-config-next": "16.0.1", "tailwindcss": "^4", "typescript": "^5" } this is my package json dependencies and devDependencies
'use client'; import Slider from 'react-slick'; import 'slick-carousel/slick/slick.css'; export default function Home() { var settings = { dots: true, infinite: false, speed: 500, slidesToShow: 4, slidesToScroll: 4, initialSlide: 0, responsive: [ { breakpoint: 1024, settings: { slidesToShow: 3, slidesToScroll: 3, infinite: true, dots: true, }, }, { breakpoint: 600, settings: { slidesToShow: 2, slidesToScroll: 2, initialSlide: 2, }, }, { breakpoint: 480, settings: { slidesToShow: 1, slidesToScroll: 1, }, }, ], }; return ( <div className=""> <div className="slider-container"> <Slider {...settings}>
issue is breakpoint settings are not woking in responsive
Yes same issue I am facing
It seems to be an issue with the latest version, 0.31.0. When installing the 0.30.3 version, it works as intended.
I am running into this issue as well. From what I can tell, for me the issue is the react-slick Slider component is only checking the current windows width on window resize, but not on initial render. So instead of using the appropriate settings set via the responsive prop on render, it will instead use the defaults UNTIL you resize the window AND the resize hits a breakpoint defined in the responsive prop.
I was able to reproduce this behavior in the responsive playwright test. Here are the settings being used by the responsive tests:
https://github.com/akiran/react-slick/blob/97442318e9a442bd4a84eb25133ef62087f98232/playwright-tests/features/responsive/responsive.story.tsx#L5-L38
In the test spec responsive.spec.tsx, If you change the initial viewport from 1200x500 to 1020x500, you would expect the first test to fail since 1000 width is within the 3 active slides breakpoint:
await expect(await activeSlidesCount(component)).toEqual(4);
however its the second test that fails:
await page.setViewportSize({ width: 1000, height: 500 });
await page.waitForTimeout(100);
await expect(await activeSlidesCount(component)).toEqual(3);
since even though the viewport changed, it didn't pass a breakpoint, so react-slider did not update the settings based on the responsive attribute.
Found the problematic code (it stems from react-slider moving away from using enquire.js and using window.watchMedia instead). I pushed a PR that I believe fixes this issue, so hopefully it will get merged soon. Until then, downgrading to version 0.30.3 like @tutagomes mentioned is the current workaround.
I've solved the problem by make custom hook that act like the responsive property in the library
import { useEffect, useState } from "react";
/**
* React hook to run callbacks when the window width crosses specified breakpoints.
*
* @typedef {Object} UseMediaQueryParam
* @property {number} breakpoint - Breakpoint width in pixels.
* @property {function(): void} onChange - Callback invoked when the viewport crosses the breakpoint.
*
* @param {UseMediaQueryParam[]} breakpoints - Array of breakpoint definitions.
* @returns {void}
*/
export function useMediaQuery(breakpoints) {
const [innerWidth, setInnerWidth] = useState(typeof window !== "undefined" ? window.innerWidth : 0);
useEffect(() => {
function handleResize() {
setInnerWidth(window.innerWidth);
}
handleResize();
window.addEventListener("resize", handleResize);
return () => {
window.removeEventListener("resize", handleResize);
};
}, []);
useEffect(() => {
breakpoints.forEach(({ breakpoint, onChange }) => {
if (innerWidth <= breakpoint) {
onChange();
}
});
}, [innerWidth]);
}
first wrap the carousel settings in state, then use the hook like this
useMediaQuery([
{
breakpoint: Infinity,
onChange: () => {
setCarouselSettings((prev) => ({
...prev,
slidesToShow: 4,
slidesToScroll: 2,
}));
},
},
...
])
note: i write the code in JS, because my team it still using JS :)
The breakpoints were working for me when I resized the window, but the initial load wasn't. Not sure why, but what fixed this for me was sorting the breakpoints array myself.
My hunch is telling me, some calculation is happening when the component mounts but not when the number of children changes. I start with an empty array, then a loading item one, the the real data once it's done fetching.
here is the updated typescript version of the proposed useMediaQuery fix been proposed above
useMediaQuery hook
import { useEffect, useState } from "react";
export interface UseMediaQueryParam {
breakpoint: number;
onChange: () => void;
}
/**
* React hook to run callbacks when the window width crosses specified breakpoints.
*/
export function useMediaQuery(breakpoints: UseMediaQueryParam[]): void {
const [innerWidth, setInnerWidth] = useState(
typeof window !== "undefined" ? window.innerWidth : 0
);
useEffect(() => {
const handleResize = () => {
setInnerWidth(window.innerWidth);
};
handleResize();
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);
useEffect(() => {
const sorted = [...breakpoints].sort((a, b) => a.breakpoint - b.breakpoint);
const match = sorted.find((bp) => innerWidth <= bp.breakpoint);
if (match) {
match.onChange();
}
}, [innerWidth, breakpoints]);
}
and here is its usage
useSliderSettings hook
import { useState } from "react";
import { useMediaQuery } from "./useMediaQuery"; // import your hook
export function useSliderSettings() {
const [slidesToShow, setSlidesToShow] = useState(4);
const [currentSlide, setCurrentSlide] = useState(0);
useMediaQuery([
{
breakpoint: 500,
onChange: () => {
setSlidesToShow(1);
},
},
{
breakpoint: 900,
onChange: () => setSlidesToShow(2),
},
{
breakpoint: 1280,
onChange: () => setSlidesToShow(3),
},
{
breakpoint: 1560,
onChange: () => setSlidesToShow(3),
},
{
breakpoint: 3600,
onChange: () => setSlidesToShow(4),
},
]);
return {
dots: false,
infinite: false,
speed: 500,
slidesToShow,
slidesToScroll: 1,
arrows: false,
swipeToSlide: true,
afterChange: (index: number) => setCurrentSlide(index),
currentSlide,
};
}
and it can now be called within your component level
const settings = useSliderSettings();
I've solved the problem by make custom hook that act like the responsive property in the library
import { useEffect, useState } from "react"; /** * React hook to run callbacks when the window width crosses specified breakpoints. * * @typedef {Object} UseMediaQueryParam * @property {number} breakpoint - Breakpoint width in pixels. * @property {function(): void} onChange - Callback invoked when the viewport crosses the breakpoint. * * @param {UseMediaQueryParam[]} breakpoints - Array of breakpoint definitions. * @returns {void} */ export function useMediaQuery(breakpoints) { const [innerWidth, setInnerWidth] = useState(typeof window !== "undefined" ? window.innerWidth : 0); useEffect(() => { function handleResize() { setInnerWidth(window.innerWidth); } handleResize(); window.addEventListener("resize", handleResize); return () => { window.removeEventListener("resize", handleResize); }; }, []); useEffect(() => { breakpoints.forEach(({ breakpoint, onChange }) => { if (innerWidth <= breakpoint) { onChange(); } }); }, [innerWidth]); }first wrap the carousel settings in state, then use the hook like this
useMediaQuery([ { breakpoint: Infinity, onChange: () => { setCarouselSettings((prev) => ({ ...prev, slidesToShow: 4, slidesToScroll: 2, })); }, }, ... ])note: i write the code in JS, because my team it still using JS :)
thanks for this code snippet