Skip to content

Instantly share code, notes, and snippets.

@gabrielmlinassi
Created June 13, 2022 18:28
Show Gist options
  • Save gabrielmlinassi/91624dcb1f8b137efb7de46f2dcfbac3 to your computer and use it in GitHub Desktop.
Save gabrielmlinassi/91624dcb1f8b137efb7de46f2dcfbac3 to your computer and use it in GitHub Desktop.
Responsive embla carousel with slidesPerView prop without CLS (Comulative Layout Shift)
//---------------
// implementation:
import styled from "styled-components";
import { useCarousel } from "./useCarousel";
type CarouselProps = {
slides: React.ReactNode[];
/** [mobile, tablet, desktop] */
slidesPerView: [number, number, number];
};
const Carousel = ({ slides, slidesPerView }: CarouselProps) => {
const carousel = useCarousel();
return (
<StyledCarousel ref={carousel.ref} {...{ slidesPerView }}>
<StyledCarouselContainer>
{slides.map((slide, i) => (
<StyledCarouselSlide key={i} {...{ slidesPerView }}>
{slide}
</StyledCarouselSlide>
))}
</StyledCarouselContainer>
</StyledCarousel>
);
};
const StyledCarousel = styled.div<Pick<CarouselProps, "slidesPerView">>`
overflow: hidden;
margin-right: -1rem;
&::before {
display: none;
content: ${({ slidesPerView }) =>
`'{ "slidesToScroll": ${slidesPerView[0]} }'`};
}
@media only screen and (min-width: 768px) {
&::before {
display: none;
content: ${({ slidesPerView }) =>
`'{ "slidesToScroll": ${slidesPerView[1]} }'`};
}
}
@media only screen and (min-width: 1024px) {
&::before {
display: none;
content: ${({ slidesPerView }) =>
`'{ "slidesToScroll": ${slidesPerView[2]} }'`};
}
}
`;
const StyledCarouselContainer = styled.div`
display: flex;
gap: 1rem;
`;
const StyledCarouselSlide = styled.div<Pick<CarouselProps, "slidesPerView">>`
position: relative;
flex: ${({ slidesPerView }) =>
`0 0 calc((100% / ${slidesPerView[0]}) - 1rem)`};
@media only screen and (min-width: 768px) {
flex: ${({ slidesPerView }) =>
`0 0 calc((100% / ${slidesPerView[1]}) - 1rem)`};
}
@media only screen and (min-width: 1024px) {
flex: ${({ slidesPerView }) =>
`0 0 calc((100% / ${slidesPerView[2]}) - 1rem)`};
}
`;
export default Carousel;
//--------------
// usage:
<Carousel
slides={Certificates.map((cert) => (
<Certificate
key={cert.serial}
certificate={cert}
autosize
compact
/>
))}
slidesPerView={[1.1, 2, 4]}
/>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment