I'm Using react responsive carousel in my Next JS app with tailwind. how can customize next and prev button to circular shape?
<Carousel axis="horizontal" showStatus={false}>
<div className="w-full relative pt-[100%]">
<Image
src={house.img}
alt="profile"
objectFit="cover"
fill
className="w-full h-full top-0 left-0 object-cover rounded-2xl"
/>
</div>
<div className="w-full relative pt-[100%]">
<Image
src={house.img}
alt="profile"
objectFit="cover"
fill
className="w-full h-full top-0 left-0 object-cover rounded-2xl"
/>
</div>
<div className="w-full relative pt-[100%]">
<Image
src={house.img}
alt="profile"
objectFit="cover"
fill
className="w-full h-full top-0 left-0 object-cover rounded-2xl"
/>
</div>
</Carousel>
According to the document of react-responsive-carousel, it seems that the arrows can be customized with the props renderArrowPrev and renderArrowNext on the Carousel component.
Assuming that there is a LeftIcon and a RightIcon that needed to replace the default arrows, here is a very basic example. It can be further customized with Tailwind to fit the use case.
Over simplified live demo: stackblitz (this demo used arrow icons from react-icons for convenience, but it can be customized as any custom icons preferred)
<Carousel
axis="horizontal"
showStatus={false}
className="relative"
renderArrowPrev={(clickHandler, hasPrev) => {
return (
<div
className={`${
hasPrev ? "absolute" : "hidden"
} top-0 bottom-0 left-0 flex justify-center items-center p-3 opacity-30 hover:opacity-100 cursor-pointer z-20`}
onClick={clickHandler}
>
<LeftIcon className="w-9 h-9 text-white" />
</div>
);
}}
renderArrowNext={(clickHandler, hasNext) => {
return (
<div
className={`${
hasNext ? "absolute" : "hidden"
} top-0 bottom-0 right-0 flex justify-center items-center p-3 opacity-30 hover:opacity-100 cursor-pointer z-20`}
onClick={clickHandler}
>
<RightIcon className="w-9 h-9 text-white" />
</div>
);
}}
>
<div className="w-full relative pt-[100%]">
<Image
src={house.img}
alt="profile"
objectFit="cover"
fill
className="w-full h-full top-0 left-0 object-cover rounded-2xl"
/>
</div>
<div className="w-full relative pt-[100%]">
<Image
src={house.img}
alt="profile"
objectFit="cover"
fill
className="w-full h-full top-0 left-0 object-cover rounded-2xl"
/>
</div>
<div className="w-full relative pt-[100%]">
<Image
src={house.img}
alt="profile"
objectFit="cover"
fill
className="w-full h-full top-0 left-0 object-cover rounded-2xl"
/>
</div>
</Carousel>
Related
I'm using the headless UI's select to choose a dev name, when I open it and I choose the option sometimes he keeps opened but insivible, then I need to click again in some option to actually close the select.
Here's the code:
<div>
<Listbox value={selected} onChange={setSelected}>
<div className=" mt-1 z-40">
<Listbox.Button className="relative w-full cursor-pointer rounded-lg bg-base-200 border-none text-left sm:text-sm">
<span className="block truncate">{selected}</span>
</Listbox.Button>
<Transition
as={Fragment}
leave="transition ease-in duration-100"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Listbox.Options className="mt-1 z-40 max-h-60 absolute px-4 box-border w-1/6 overflow-auto rounded-md bg-base-300 py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm">
{arrayDevs?.map((newDev: string) => (
<Listbox.Option
onClick={() => updateTaskDev(newDev)}
key={newDev}
className={({ active }) =>
`relative cursor-default select-none py-2 pl-2 pr-4 rounded-lg list-none ${
active ? "bg-primary text-white" : "text-base-content"
}`
}
value={newDev}
>
{({ selected }) => (
<>
<span
className={`block truncate ${
selected ? "font-medium" : "font-normal"
}`}
>
{newDev}
</span>
</>
)}
</Listbox.Option>
))}
</Listbox.Options>
</Transition>
</div>
</Listbox>
</div>
I'm using next JS with tailwind css and using react-responsive-carousel package.the issue that i'm having is that when i start to swipe the images they're next to each other horizontally. they have no effect (like fade or ease in out) to them while swiping. and i wanted to make animation transition with ease-in-out or fade to it. how can i add fade in out animation instead of its default slide?
<Carousel
swipeScrollTolerance={100}
preventMovementUntilSwipeScrollTolerance
key={house.id}
axis="horizontal"
showStatus={false}
showThumbs={false}
swipeable={true}
className="group "
renderIndicator={(onClickHandler, isSelected, index, label) => {
const defStyle = {
marginLeft: 6,
color: "#b9b9b9",
cursor: "pointer",
};
const style = isSelected
? { ...defStyle, color: "#dcdcdc" }
: { ...defStyle };
return (
<span
style={style}
onClick={onClickHandler}
onKeyDown={onClickHandler}
value={index}
key={index}
role="button"
tabIndex={0}
aria-label={`${label} ${index + 1}`}
>
<FontAwesomeIcon
icon={faCircle}
className="sm:h-[0.35rem] sm:w-[0.35rem] h-2 w-2 font-thin"
/>
</span>
);
}}
renderArrowPrev={(clickHandler, hasPrev) => {
return (
<div
className={`${
hasPrev && !toggle ? "absolute" : "hidden"
} top-0 bottom-0 left-0 flex justify-center items-center p-3 opacity-0 group-hover:opacity-70 cursor-pointer z-10 text-white`}
onClick={clickHandler}
>
<FontAwesomeIcon
icon={faChevronCircleLeft}
className="h-8 w-8 font-thin"
/>
</div>
);
}}
renderArrowNext={(clickHandler, hasNext) => {
return (
<div
className={`${
hasNext && !toggle ? "absolute" : "hidden"
} top-0 bottom-0 right-0 flex justify-center items-center p-3 opacity-0 group-hover:opacity-70 cursor-pointerz-10 text-white`}
onClick={clickHandler}
>
<FontAwesomeIcon
icon={faChevronCircleRight}
className="h-8 w-8 font-thin"
/>
</div>
);
}}
>
{house.img.map((img, index) => {
return (
<Link href={`/living/${house.id}`} key={img.id}>
<div
key={img.id}
className=" w-full relative -z-10 pt-[100%] cursor-pointer"
>
<Image
src={img.img}
alt="profile"
fill
className="w-full h-full top-0 left-0 -z-10 object-cover rounded-2xl ease-in-out duration-200"
/>
</div>
</Link>
);
})}
</Carousel>
I have a page /enroll where there is a select dropdown menu, which is another component:
const roles = [
{ id: 1, name: 'Business Analyst' },
{ id: 2, name: 'Data Analyst' },
{ id: 3, name: 'Quality Assurance Analyst' },
{ id: 4, name: 'UI/UX Designer' },
]
const Dropdown = () => {
const [selected, setSelected] = useState(people[0])
return (
<Listbox value={selected} onChange={setSelected}>
{({ open }) => (
<>
<Listbox.Label className="block text-sm font-medium text-gray-700">Interested Role</Listbox.Label>
<div className="relative mt-1">
<Listbox.Button className="relative w-full cursor-default rounded-md border border-gray-300 bg-white py-2 pl-3 pr-10 text-left shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500 sm:text-sm">
<span className="block truncate">{selected.name}</span>
<span className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
<ChevronUpDownIcon className="h-5 w-5 text-gray-400" aria-hidden="true" />
</span>
</Listbox.Button>
<Transition
show={open}
as={Fragment}
leave="transition ease-in duration-100"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Listbox.Options className="absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm">
{people.map((person) => (
<Listbox.Option
key={person.id}
className={({ active }) =>
classNames(
active ? 'text-white bg-indigo-600' : 'text-gray-900',
'relative cursor-default select-none py-2 pl-3 pr-9'
)
}
value={person}
>
{({ selected, active }) => (
<>
<span className={classNames(selected ? 'font-semibold' : 'font-normal', 'block truncate')}>
{person.name}
</span>
{selected ? (
<span
className={classNames(
active ? 'text-white' : 'text-indigo-600',
'absolute inset-y-0 right-0 flex items-center pr-4'
)}
>
<CheckIcon className="h-5 w-5" aria-hidden="true" />
</span>
) : null}
</>
)}
</Listbox.Option>
))}
</Listbox.Options>
</Transition>
</div>
</>
)}
</Listbox>
)
}
export default Dropdown
I need the value of the selected option on the enroll page. This is how the component is being called on the /enroll page:
<div className="">
<Dropdown />
</div>
How do I know what value was selected in the dropdown?
P.S. Next.js is used here.
This is what the /enroll page form looks like:
So My page looks like below
I have written a logic to open a modal using headlessui on clicking one of the sub hoodie images.
This works perfectly , but after I close it, the scrolling of the page disables and an extra
style="overflow: hidden; padding-right: 16px;"
is getting added to my main html tag.
Below is the reference
How do i stop the modal to automatically apply padding and overflow.
A lot of people have had this problem with bootstrap but i am not able to find this issue resolved in tailwind. Please help
below is the code for my modal
import React from 'react'
import { Dialog, Transition } from '#headlessui/react'
import { Fragment } from 'react'
import {XIcon} from '#heroicons/react/solid'
import {useRecoilState} from 'recoil'
import {openState} from '../../../atoms/modalAtom'
const product = {
name: "Women's Basic Tee",
price: '$32',
rating: 3.9,
reviewCount: 512,
href: '#',
imageSrc: 'https://tailwindui.com/img/ecommerce-images/product-page-01-featured-product-shot.jpg',
imageAlt: "Back of women's Basic Tee in black.",
colors: [
{ name: 'Black', bgColor: 'bg-gray-900', selectedColor: 'ring-gray-900' },
{ name: 'Heather Grey', bgColor: 'bg-gray-400', selectedColor: 'ring-gray-400' },
],
sizes: [
{ name: 'XXS', inStock: true },
{ name: 'XS', inStock: true },
{ name: 'S', inStock: true },
{ name: 'M', inStock: true },
{ name: 'L', inStock: true },
{ name: 'XL', inStock: true },
{ name: 'XXL', inStock: false },
],
}
export function DesignQuickView ({design}) {
const [open, setOpen] = useRecoilState(openState)
return (
<Transition.Root show={open} as={Fragment}>
<Dialog as="div" className="relative z-10" onClose={() => setOpen(false)}>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="hidden fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity md:block" />
</Transition.Child>
<div className="fixed z-10 inset-0 overflow-y-auto">
<div className="flex items-stretch md:items-center justify-center min-h-full text-center md:px-2 lg:px-4">
{/* This element is to trick the browser into centering the modal contents. */}
<span className="hidden md:inline-block md:align-middle md:h-screen" aria-hidden="true">
</span>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 translate-y-4 md:translate-y-0 md:scale-95"
enterTo="opacity-100 translate-y-0 md:scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 translate-y-0 md:scale-100"
leaveTo="opacity-0 translate-y-4 md:translate-y-0 md:scale-95"
>
<Dialog.Panel className="flex text-base text-left transform transition w-full md:max-w-2xl md:px-4 md:my-8 lg:max-w-4xl">
<div className="w-full relative flex items-center bg-white px-4 pt-14 pb-8 overflow-hidden shadow-2xl sm:px-6 sm:pt-8 md:p-6 lg:p-8">
<button
type="button"
className="absolute top-4 right-4 text-gray-400 hover:text-gray-500 sm:top-8 sm:right-6 md:top-6 md:right-6 lg:top-8 lg:right-8"
onClick={() => setOpen(false)}
>
<span className="sr-only">Close</span>
<XIcon className="h-6 w-6" aria-hidden="true" />
</button>
<div className="w-full grid grid-cols-1 gap-y-8 gap-x-6 items-start sm:grid-cols-12 lg:items-center lg:gap-x-8">
<div className="aspect-w-3 aspect-h-4 rounded-lg bg-gray-100 overflow-hidden sm:col-span-4 lg:col-span-5">
<img src={design.url} alt={design.name} className="object-center object-cover" />
</div>
<div className="sm:col-span-8 lg:col-span-7">
<h2 className="text-xl font-medium text-gray-900 sm:pr-12">Hoodie</h2>
<section aria-labelledby="information-heading" className="mt-1">
<h3 id="information-heading" className="sr-only">
Product information
</h3>
<p className="font-medium text-gray-900">{product.price}</p>
</section>
<section aria-labelledby="options-heading" className="mt-8">
<h3 id="options-heading" className="sr-only">
Product options
</h3>
<form>
{/* Color picker */}
<div>
<h4 className="text-sm font-medium text-gray-900">Color</h4>
{/* <RadioGroup value={selectedColor} onChange={setSelectedColor} className="mt-2">
<RadioGroup.Label className="sr-only">Choose a color</RadioGroup.Label>
<div className="flex items-center space-x-3">
{product.colors.map((color) => (
<RadioGroup.Option
key={color.name}
value={color}
className={({ active, checked }) =>
classNames(
color.selectedColor,
active && checked ? 'ring ring-offset-1' : '',
!active && checked ? 'ring-2' : '',
'-m-0.5 relative p-0.5 rounded-full flex items-center justify-center cursor-pointer focus:outline-none'
)
}
>
<RadioGroup.Label as="span" className="sr-only">
{color.name}
</RadioGroup.Label>
<span
aria-hidden="true"
className={classNames(
color.bgColor,
'h-8 w-8 border border-black border-opacity-10 rounded-full'
)}
/>
</RadioGroup.Option>
))}
</div>
</RadioGroup> */}
</div>
{/* Size picker */}
<div className="mt-8">
<div className="flex items-center justify-between">
<h4 className="text-sm font-medium text-gray-900">Size</h4>
<a href="#" className="text-sm font-medium text-indigo-600 hover:text-indigo-500">
Size guide
</a>
</div>
{/* <RadioGroup value={selectedSize} onChange={setSelectedSize} className="mt-2">
<RadioGroup.Label className="sr-only">Choose a size</RadioGroup.Label>
<div className="grid grid-cols-7 gap-2">
{product.sizes.map((size) => (
<RadioGroup.Option
key={size.name}
value={size}
className={({ active, checked }) =>
classNames(
size.inStock
? 'cursor-pointer focus:outline-none'
: 'opacity-25 cursor-not-allowed',
active ? 'ring-2 ring-offset-2 ring-indigo-500' : '',
checked
? 'bg-indigo-600 border-transparent text-white hover:bg-indigo-700'
: 'bg-white border-gray-200 text-gray-900 hover:bg-gray-50',
'border rounded-md py-3 px-3 flex items-center justify-center text-sm font-medium uppercase sm:flex-1'
)
}
disabled={!size.inStock}
>
<RadioGroup.Label as="span">{size.name}</RadioGroup.Label>
</RadioGroup.Option>
))}
</div>
</RadioGroup> */}
</div>
</form>
</section>
</div>
</div>
</div>
</Dialog.Panel>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition.Root>
)
}
export default DesignQuickView
In the closeModal function, you can override the style of the html tag:
function closeModal() {
setOpen(false);
setTimeout(() => {
const html = document.body.parentNode as HTMLElement | null;
html.classList.add('modal_close');
}, 50);
}
function openModal() {
setOpen(true);
const html = document.body.parentNode as HTMLElement | null;
html.classList.remove('modal_close');
}
<Dialog as="div" className="relative z-10" onClose={closeModal}><
<button
type="button"
className="absolute top-4 right-4 text-gray-400 hover:text-gray-500 sm:top-8 sm:right-6 md:top-6 md:right-6 lg:top-8 lg:right-8"
onClick={closeModal}
>
style.css
.modal_close {
overflow: auto !important;
padding-right: 0px !important;
}
I reused the promotion-slider.js swiper code in another FlashDealsProducts.js file with
some changes but without any error both components slides in same direction when I click
either of the slide button. I tried changing the id but it didn't worked.
Deleted dummy data of both file
Promotion-Slider.js file
import { ArrowNext, ArrowPrev } from "#components/icons";
import SwiperCore, { Navigation } from "swiper";
import { Swiper, SwiperSlide } from "swiper/react";
import "swiper/swiper-bundle.css";
const offerSliderBreakpoints = {
320: {
slidesPerView: 1,
spaceBetween: 0,
},
580: {
slidesPerView: 2,
spaceBetween: 16,
},
1024: {
slidesPerView: 3,
spaceBetween: 16,
},
1920: {
slidesPerView: 4,
spaceBetween: 24,
},
};
SwiperCore.use([Navigation]);
export default function PromotionSlider() {
return (
<div className="px-6 py-5 md:px-8 xl:px-12 md:py-10 border-t border-gray-200">
<div className="relative">
<Swiper
// id="offer"
loop={true}
breakpoints={offerSliderBreakpoints}
navigation={{
nextEl: ".next",
prevEl: ".prev",
}}
>
{data?.map((d) => (
<SwiperSlide key={d.id}>
<img
className="w-full h-auto"
src={d.bannerUrl}
alt={d.title}
width="430"
height="200"
/>
</SwiperSlide>
))}
</Swiper>
<div
className="prev cursor-pointer absolute top-2/4 -left-4 md:-left-5 z-10 -mt-4 md:-mt-5 w-8 h-8 md:w-9 md:h-9 rounded-full bg-white shadow-xl border border-gray-200 border-opacity-70 flex items-center justify-center text-gray-800 transition-all duration-200 hover:bg-primary hover:text-white hover:border-primary"
role="button"
>
<span className="sr-only">previous</span>
<ArrowPrev width={18} height={18} />
</div>
<div
className="next cursor-pointer absolute top-2/4 -right-4 md:-right-5 z-10 -mt-4 md:-mt-5 w-8 h-8 md:w-9 md:h-9 rounded-full bg-white shadow-xl border border-gray-200 border-opacity-70 flex items-center justify-center text-gray-800 transition-all duration-200 hover:bg-primary hover:text-white hover:border-primary"
role="button"
>
<span className="sr-only">next</span>
<ArrowNext width={18} height={18} />
</div>
</div>
</div>
);
}
FlashDealsProducts.js file
import Products from './Products.js';
import ProductCard from './ProductCard.js';
import { ArrowNext, ArrowPrev } from "#components/icons";
import SwiperCore, { Navigation } from "swiper";
import { Swiper, SwiperSlide } from "swiper/react";
import "swiper/swiper-bundle.css";
const SliderBreakpoints = {
320: {
slidesPerView: 1,
spaceBetween: 0,
},
580: {
slidesPerView: 2,
spaceBetween: 16,
},
1024: {
slidesPerView: 3,
spaceBetween: 16,
},
1920: {
slidesPerView: 4,
spaceBetween: 24,
},
};
SwiperCore.use([Navigation]);
export default function FlashDealProducts() {
return (
<div className='flex mt-14 flex-col'>
<div className='flex pl-1 flex-nowrap bg-white p-4'>
<h2 className=' flex-nowrap ml-7 font-bold text-lg'> Flash Deals </h2>
<span className='text-sm ml-20 font-light text-gray-800 '> Ends in </span>
<span className='px-1 ml-4 bg-red-700 text-white font-medium'> 10 hours</span>
</div>
<div className="px-6 py-5 md:px-8 xl:px-12 md:py-10 border-t bg-white border-gray-200">
<div className="relative">
<Swiper
id="flash-deals"
loop={true}
breakpoints={SliderBreakpoints}
navigation={{
nextEl: ".next",
prevEl: ".prev",
}}
>
{Products?.map((d) => (
<SwiperSlide key={d.id}>
<ProductCard key={d.id}
title={d.title}
image={d.image}
basePrice={d.basePrice}
flashHeight={200}
flashWidth={200}
discount={d.discount}
currentPrice={d.currentPrice} />
</SwiperSlide>
))}
</Swiper>
<div
className="prev cursor-pointer absolute top-2/4 -left-4 md:-left-5 z-10 -mt-4 md:-mt-5 w-8 h-8 md:w-9 md:h-9 rounded-full bg-white shadow-xl border border-gray-200 border-opacity-70 flex items-center justify-center text-gray-800 transition-all duration-200 hover:bg-primary hover:text-white hover:border-primary"
role="button"
>
<span className="sr-only">previous</span>
<ArrowPrev width={18} height={18} />
</div>
<div
className="next cursor-pointer absolute top-2/4 -right-4 md:-right-5 z-10 -mt-4 md:-mt-5 w-8 h-8 md:w-9 md:h-9 rounded-full bg-white shadow-xl border border-gray-200 border-opacity-70 flex items-center justify-center text-gray-800 transition-all duration-200 hover:bg-primary hover:text-white hover:border-primary"
role="button"
>
<span className="sr-only">next</span>
<ArrowNext width={18} height={18} />
</div>
</div>
</div>
{/* </div> */}
</div>
)
}
Check, both values of navigation object in both files are same.
Assign different values to prevEl and nextEl property for every swiper
component you use in your project.
navigation={{
nextEl: ".next", // both should be unique in every swiper
// component
prevEl: ".prev",
}}
Either you change both values or one of them in your file only if you
are using two swiper component in your project else you have to assign
different values to navigation property in every swiper component.
Make sure to replace it with new value in classes below.