Home > Mobile >  How to use NextJS Component level CSS
How to use NextJS Component level CSS

Time:05-28

I'm not very good at CSS, in fact, I barely write CSS due to the rise of libraries like MUI. I have found myself in a weird situation, I'm trying to rewrite this sample Code structure

The ProductSlider.tsx is the EmblaCarousel.js in the sample project, the ProductSlider.module.css is the embla.css

My ProductSlider looks like this:

import s from './ProductSlider.module.css'
import React, { useState, useEffect, useCallback, memo } from 'react'
import useEmblaCarousel from 'embla-carousel-react'
import Thumbnail from './Thumbnail'
import Image from 'next/image'
import { Box } from '@mui/material'

type ProductSliderProps = {
items: {
    url: string
    alt?: string
}[]
}

const ProductSlider = ({ items }: ProductSliderProps) => {
const [selectedIndex, setSelectedIndex] = useState(0)
const [mainViewportRef, embla] = useEmblaCarousel({ skipSnaps: false })
const [thumbViewportRef, emblaThumbs] = useEmblaCarousel({
    containScroll: 'keepSnaps',
    dragFree: true,
})

const onThumbClick = useCallback(
    (index) => {
    if (!embla || !emblaThumbs) return
    if (emblaThumbs.clickAllowed()) embla.scrollTo(index)
    },
    [embla, emblaThumbs]
)

const onSelect = useCallback(() => {
    if (!embla || !emblaThumbs) return
    setSelectedIndex(embla.selectedScrollSnap())
    emblaThumbs.scrollTo(embla.selectedScrollSnap())
}, [embla, emblaThumbs, setSelectedIndex])

useEffect(() => {
    if (!embla) return
    onSelect()
    embla.on('select', onSelect)
}, [embla, onSelect])

return (
    <>
    <Box className={s.embla}>
        <Box className={s.embla__viewport} ref={mainViewportRef}>
        <Box className={s.embla__container}>
            {items.map(({ url, alt }, idx) => (
            <Box className={s.embla__slide} key={idx}>
                <Box className={s.embla__slide__inner}>
                <Image
                    src={url}
                    alt={alt}
                    layout="fill"
                    objectFit="contain"
                    quality="85"
                />
                </Box>
            </Box>
            ))}
        </Box>
        </Box>
    </Box>

    <Box className="embla embla--thumb">
        <Box className={s.embla__viewport} ref={thumbViewportRef}>
        <Box className="embla__container embla__container--thumb">
            {items.map(({ url, alt }, idx) => (
            <Thumbnail
                onClick={() => onThumbClick(idx)}
                selected={idx === selectedIndex}
                imgSrc={url}
                key={idx}
                alt={alt}
                s={s}
            />
            ))}
        </Box>
        </Box>
    </Box>
    </>
)
}

export default memo(ProductSlider)

As you can see I have managed to get the straightforward CSS working, the challenge is, how do I call something like this embla__container embla__container--thumb using the named import?

or this

<div
className={`embla__slide embla__slide--thumb ${
selected ? 'is-selected' : ''
}`}

I understand in cases where I have two classes like this embla__container embla__container I can use clsx like this cn(s.embla__container, s.embla__container) but in a case where I have something like this --thumb, some_name--thumb, some_name-is-selected or this is-selected I'm not sure what to do.

CodePudding user response:

Try to do this

import s from './ProductSlider.module.css'
import React, { useState, useEffect, useCallback, memo } from 'react'
import useEmblaCarousel from 'embla-carousel-react'
import Thumbnail from './Thumbnail'
import Image from 'next/image'
import { Box } from '@mui/material'

type ProductSliderProps = {
items: {
    url: string
    alt?: string
}[]
}

const ProductSlider = ({ items }: ProductSliderProps) => {
const [selectedIndex, setSelectedIndex] = useState(0)
const [mainViewportRef, embla] = useEmblaCarousel({ skipSnaps: false })
const [thumbViewportRef, emblaThumbs] = useEmblaCarousel({
    containScroll: 'keepSnaps',
    dragFree: true,
})

const onThumbClick = useCallback(
    (index) => {
    if (!embla || !emblaThumbs) return
    if (emblaThumbs.clickAllowed()) embla.scrollTo(index)
    },
    [embla, emblaThumbs]
)

const onSelect = useCallback(() => {
    if (!embla || !emblaThumbs) return
    setSelectedIndex(embla.selectedScrollSnap())
    emblaThumbs.scrollTo(embla.selectedScrollSnap())
}, [embla, emblaThumbs, setSelectedIndex])

useEffect(() => {
    if (!embla) return
    onSelect()
    embla.on('select', onSelect)
}, [embla, onSelect])

return (
    <>
    <Box className={s.embla}>
        <Box className={s.embla__viewport} ref={mainViewportRef}>
        <Box className={s.embla__container}>
            {items.map(({ url, alt }, idx) => (
            <Box className={s.embla__slide} key={idx}>
                <Box className={s.embla__slide__inner}>
                <Image
                    src={url}
                    alt={alt}
                    layout="fill"
                    objectFit="contain"
                    quality="85"
                />
                </Box>
            </Box>
            ))}
        </Box>
        </Box>
    </Box>

    <Box className="embla embla--thumb">
        <Box className={s.embla__viewport} ref={thumbViewportRef}>
        <Box className="embla__container embla__container--thumb">
            {items.map(({ url, alt }, idx) => (
            <Thumbnail
                onClick={() => onThumbClick(idx)}
                selected={idx === selectedIndex}
                imgSrc={url}
                key={idx}
                alt={alt}
                s={s}
            />
            ))}
        </Box>
        </Box>
    </Box>




    <style>
        {
        `
        // Your Css Here     
        
        
        `
        }
    </style>

    </>
)
}

export default memo(ProductSlider)

CodePudding user response:

Based on this answer I ended up doing this and it worked:

import s from './ProductSlider.module.css'
import React, { useState, useEffect, useCallback, memo } from 'react'
import useEmblaCarousel from 'embla-carousel-react'
import Thumbnail from './Thumbnail'
import Image from 'next/image'
import { Box } from '@mui/material'

type ProductSliderProps = {
items: {
    url: string
    alt?: string
}[]
}

const ProductSlider = ({ items }: ProductSliderProps) => {
const [selectedIndex, setSelectedIndex] = useState(0)
const [mainViewportRef, embla] = useEmblaCarousel({ skipSnaps: false })
const [thumbViewportRef, emblaThumbs] = useEmblaCarousel({
    containScroll: 'keepSnaps',
    dragFree: true,
})

const onThumbClick = useCallback(
    (index) => {
    if (!embla || !emblaThumbs) return
    if (emblaThumbs.clickAllowed()) embla.scrollTo(index)
    },
    [embla, emblaThumbs]
)

const onSelect = useCallback(() => {
    if (!embla || !emblaThumbs) return
    setSelectedIndex(embla.selectedScrollSnap())
    emblaThumbs.scrollTo(embla.selectedScrollSnap())
}, [embla, emblaThumbs, setSelectedIndex])

useEffect(() => {
    if (!embla) return
    onSelect()
    embla.on('select', onSelect)
}, [embla, onSelect])

return (
    <>
    <Box className={s.embla}>
        <Box className={s.embla__viewport} ref={mainViewportRef}>
        <Box className={s.embla__container}>
            {items.map(({ url, alt }, idx) => (
            <Box className={s.embla__slide} key={idx}>
                <Box className={s.embla__slide__inner}>
                <Image
                    src={url}
                    alt={alt}
                    layout="fill"
                    objectFit="contain"
                    quality="85"
                />
                </Box>
            </Box>
            ))}
        </Box>
        </Box>
    </Box>

    <Box className={`${s.embla} ${s['embla--thumb']}`}>
        <Box className={s.embla__viewport} ref={thumbViewportRef}>
        <Box
            className={`${s.embla__container} ${s['embla__container--thumb']}`}
        >
            {items.map(({ url, alt }, idx) => (
            <Thumbnail
                onClick={() => onThumbClick(idx)}
                selected={idx === selectedIndex}
                imgSrc={url}
                key={idx}
                alt={alt}
                s={s}
            />
            ))}
        </Box>
        </Box>
    </Box>
    </>
)
}

export default memo(ProductSlider)
  • Related