How do i make Tailwind.css responsive? - css

I have two components.In first MovieItem.js i created a card.In second Movies.js i am looping through an array of cards and displaying them in UI - 4 per row.I am using Tailwind grid template columns to do this, and it s working fine.
return (
<div className="grid grid-cols-4 gap-4">
{movies.map((movie) => (
<MovieItem key={movie.id} movie={movie}></MovieItem>
))}
</div>
);
However if the width of the screen is less then 640 pixels i want to show only one card per row which means that each card should have width 100% and that they should be all horizontally stacked on top of each other, but i am not getting any results with this.
return (
<div className="grid grid-cols-4 sm:grid grid-cols-1 gap-4">
{movies.map((movie) => (
<MovieItem key={movie.id} movie={movie}></MovieItem>
))}
</div>
);
MovieItem.js
import React from "react";
import PropTypes from "prop-types";
import { Link } from "react-router-dom";
import AlternativeImage from "./AlternativeImage";
const MovieItem = ({ movie: { id, title, poster_path } }) => {
return (
<div className=" bg-gray-900 px-4 pt-4 pb-5 overflow-hidden rounded ">
{poster_path ? (
<img
src={"https://image.tmdb.org/t/p/w400/" + poster_path}
alt=""
className="w-full block content-center p-4 content-image"
/>
) : (
<AlternativeImage></AlternativeImage>
)}
<h6 className="text-base text-center text-white my-3 font-mono">
{title}
</h6>
<div className="button-container">
<Link
to={`/movie/${id}`}
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded "
>
Movie Details
</Link>
</div>
</div>
);
};
export default MovieItem;
Movies.js
import React, { useContext } from "react";
import MovieItem from "./MovieItem";
import MovieContext from "../context/movie/movieContext";
const Movies = () => {
const movieContext = useContext(MovieContext);
const { movies } = movieContext;
return (
<div className="grid grid-cols-4 sm:grid grid-cols-1 gap-4">
{movies.map((movie) => (
<MovieItem key={movie.id} movie={movie}></MovieItem>
))}
</div>
);
};
export default Movies;
I also made necessary changes in Tailwind config file:
const tailwindcss = require("tailwindcss");
module.exports = {
theme: {
screens: {
xl: { max: "1279px" },
// => #media (max-width: 1279px) { ... }
lg: { max: "1023px" },
// => #media (max-width: 1023px) { ... }
md: { max: "767px" },
// => #media (max-width: 767px) { ... }
sm: { max: "639px" },
// => #media (max-width: 639px) { ... }
},
},
plugins: [tailwindcss("./tailwind.js"), require("autoprefixer")],
};

By default, Tailwind uses a mobile first breakpoint system, similar to what you might be used to in Bootstrap or Foundation.
What this means is that unprefixed utilities (like uppercase) take effect on all screen sizes, while prefixed utilities (like md:uppercase) only take effect at the specified breakpoint and above.
In your case, simply do this
grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-2 md:gap-4
Check docs.

Related

Tailwind CSS custom responsive breakpoints are not working

I want to make a responsive web site using Tailwind CSS and Next.js, but I can't apply my custom responsive utility classes. I added my custom breakpoints in tailwind.config.js.
Other media queries are working fine.
I designated w-[600px] in max-1280px and w-[400px] in max-768, but I can't apply max-768 and another media query only applied max-1280px.
import React from 'react';
import profile from '../../assets/images/me.jpg';
import Image from 'next/image';
import Link from 'next/link';
import { aboutContent } from '../../data/aboutContent';
const about = () => {
return (
<div className='animate-fade-in-up'>
<h1 className='text-5xl font-appleSemiBold laptopM:text-center laptopM:underline laptopM:mb-12 tablet:text-4xl'>
About Me
</h1>
<div className='border-2 w-40 ml-[142px] mb-12 laptopM:hidden'></div>
<div className='flex flex-row justify-between items-center font-appleRegular laptopM:flex-col laptopM:gap-10'>
<Image
className='w-[600px] tablet:w-[400px]'
src={profile}
alt='Picture of me'
/>
<div className='w-6/12 laptopM:w-[600px] tablet:w-[400px]'>
<div className='text-2xl mb-8 tablet:text-xl'>
<p>test</p>
<p>
test
</p>
</div>
</div>
</div>
<div className='font-regular'></div>
</div>
);
};
export default about;
/** #type {import('tailwindcss').Config} */
module.exports = {
content: [
'./pages/**/*.{js,jsx,ts,tsx}',
'./components/**/*.{js,jsx,ts,tsx}',
],
theme: {
extend: {
screens: {
mobileS: { max: '320px' },
mobileM: { max: '375px' },
mobileL: { max: '425px' },
tablet: { max: '768px' },
laptop: { max: '1024px' },
laptopM: { max: '1280px' },
laptopL: { max: '1440px' },
},
},
plugins: [],
};

React-hydration-error every time when I put motion from framer-motion

I am facing a hydration error when trying to add motion from framer-motion in any element from the file.
Without motion, everything works fine:
import { useRef, useState, useEffect } from 'react';
import { usePathname, useRouter } from 'next/navigation';
import Image from 'next/image';
import Link from 'next/link';
import { Icon, Dropdown, UserIcon } from '#ui';
import { menuItems } from '#utils/menu';
import useOutsideClick from '#hooks/useOutsideClick';
import { useAppDispatch, useAppSelector } from '#hooks/reduxHooks';
import { triggerCloseMenu } from 'redux/Slices/menuSlice';
import { motion } from 'framer-motion';
const Header = () => {
const [url, setUrl] = useState<string>('/images/logoLight.png');
const dispatch = useAppDispatch();
const close = () => {
dispatch(triggerCloseMenu());
};
const menuOpen = useAppSelector((state) => state.menu.menuOpen);
const wrapperRef = useRef(null);
const pathname = usePathname();
const router = useRouter();
useOutsideClick(wrapperRef, close);
useEffect(() => {
setUrl(
pathname === '/'
? !menuOpen
? '/images/logoLight.png'
: '/images/logoDark.png'
: '/images/logoDark.png',
);
}, [menuOpen, pathname]);
return (
<header
className="fixed top-0 z-50 w-screen bg-transparent "
ref={wrapperRef}
>
<nav className=" mx-auto flex w-full max-w-[2000px] items-center justify-between py-9 px-7 ">
<div className="flex items-center justify-center space-x-6">
<Icon />
<Image
src={url}
alt="logo_image"
width={120}
height={0}
className="mb-1"
onClick={() => {
router.push('/');
close();
}}
/>
</div>
<div className="relative flex items-center space-x-10">
<div className="hidden space-x-14 lg:flex">
{menuItems.map((i: Menu) => (
<Link
href={i.path}
key={i.id}
className={`${
pathname !== i.path ? 'font-normal' : 'font-extrabold'
}
text-lg text-white transition duration-300 ease-linear`}
>
{i.label}
</Link>
))}
</div>
<UserIcon />
</div>
</nav>
<Dropdown />
</header>
);
};
export default Header;
But if I replace with <motion.header> </motion.header> I am getting this error : Error: Hydration failed because the initial UI does not match what was rendered on the server.
I am using latest version of Nextjs (without app directory), and framer-motion v8

GSAP Scrolltrigger PIN not working properly in nextjs

From my code below, If I comment out the pin: true property, the code works normally but the container that wraps the sections I expect to scroll horizontally are not sticky to the top. If I uncomment the pin: true, all the container (trigger) will not be visible.
Any suggestions on how to resolve this issue will be greatly appreciated.
import React, { useEffect } from "react";
import OverlayMenu from "./OverlayMenu";
import { gsap } from "gsap";
import ScrollTrigger from "gsap/dist/ScrollTrigger";
function MainContent({ overlayRef }) {
gsap.registerPlugin(ScrollTrigger);
useEffect(() => {
// alert(document.querySelector(".main__content").offsetWidth)
const sections = gsap.utils.toArray(".section");
gsap.to(sections, {
xPercent: -100 * (sections.length - 1),
ease: "none",
scrollTrigger: {
trigger: ".main__content",
scrub: 1,
markers: true,
start: "top top",
// // snap: 1 / (sections.length - 1),
end: "+=" + document.querySelector(".main__content").offsetWidth,
pin: true,
},
});
}, []);
return (
<div className="main__content__wrapper w-[calc(100%_-_80px)] h-screen ml-20">
<div className="w-full relative h-screen">
<OverlayMenu overlayRef={overlayRef} />
{/* <div className="w-full h-screen bg-black"></div> */}
<div className="main__content w-[300%] bg-purple-700 h-screen flex flex-nowrap">
<div className="section w-full h-screen- bg-red-500">1</div>
<div className="section w-full h-screen- bg-blue-500">2</div>
<div className="section w-full h-screen- bg-yellow-500">3</div>
</div>
</div>
</div>
);
}
export default MainContent;
Step back the version to 3.8.0
yarn add gsap#3.8.0
OR
npm install gsap#3.8.0
You can read more here:
https://greensock.com/forums/topic/30747-scrolltrigger-in-nextjs-build-not-working-reliably/#comment-153675
import React, { useEffect, useState } from "react";
import OverlayMenu from "./OverlayMenu";
import { gsap } from "gsap";
import ScrollTrigger from "gsap/dist/ScrollTrigger";
function MainContent({ overlayRef }) {
gsap.registerPlugin(ScrollTrigger);
const [hasRendered, setHasRendered] = useState(false);
useEffect(() => {
// ******This will set the state of hasRendered when the page render so as to keep track of the rendering steps *******
setHasRendered(true);
}, []);
useEffect(() => {
// ******* I added the conditional statement here to only create the instance of the gsap timeline ONLY after the page has rendered*******
if (hasRendered) {
// alert(document.querySelector(".main__content").offsetWidth)
const sections = gsap.utils.toArray(".section");
gsap.to(sections, {
xPercent: -100 * (sections.length - 1),
ease: "none",
scrollTrigger: {
trigger: ".main__content",
scrub: 1,
markers: true,
start: "top top",
// // snap: 1 / (sections.length - 1),
end: "+=" + document.querySelector(".main__content").offsetWidth,
pin: true,
},
});
}
}, [hasRendered]); //******** Dont forget the dependencies array too */
return (
<div className="main__content__wrapper w-[calc(100%_-_80px)] h-screen ml-20">
<div className="w-full relative h-screen">
<OverlayMenu overlayRef={overlayRef} />
{/* <div className="w-full h-screen bg-black"></div> */}
<div className="main__content w-[300%] bg-purple-700 h-screen flex flex-nowrap">
<div className="section w-full h-screen- bg-red-500">1</div>
<div className="section w-full h-screen- bg-blue-500">2</div>
<div className="section w-full h-screen- bg-yellow-500">3</div>
</div>
</div>
</div>
);
}
export default MainContent;

How can fix column property on the next fetch?

This is my first time I am asking question here. If I make any mistake, sorry from now on. I've been trying to build infinite scroll bar with 3 columns. But when the next data is fetched, the images act really weird. I've tried almost everything like "fixed, flex-nowrap", etc.. with tailwind. But none of them worked. I also made research almost for 3 hours and couldn't find any helpful resources. I'd be glad if you could help me!
video: https://streamable.com/ouk16y
import React, { useState, useEffect } from "react";
import InfiniteScroll from "react-infinite-scroll-component";
//components
//icons
import { AiOutlineHeart, AiOutlinePlus } from "react-icons/ai";
//styling
const Gallery = () => {
const apiKey = "apiKey";
const [pictures, setPictures] = useState([]);
const [page, setPage] = useState(1);
//fetching the api data
useEffect(() => {
fetch(
`https://api.unsplash.com/search/photos?page=${page}&query=office&client_id=${apiKey}`
)
.then((resp) => {
return resp.json();
})
.then((data) => {
const pictureData = [...new Set(data.results)];
setPictures((prev) => [...prev, ...pictureData]);
});
}, [page]);
return (
<InfiniteScroll
dataLength={pictures.length}
next={() => setPage((prev) => prev + 1)}
hasMore={true}
scrollThreshold={0.3}
>
<div className="columns-1 lg:columns-3 col-auto lg:w-5/6 mx-auto gap-8 space-y-4">
{pictures.map((picture) => (
<div className="" key={picture.id}>
<div className="flex p-2 lg:hidden ">
<img
className="rounded-full w-10 h-10"
src={picture.user.profile_image.medium}
alt={`${picture.name} profile`}
/>
<span className="pt-2 pl-2">{picture.user.name}</span>
</div>
<img className="resize-none" src={picture.urls.regular} />
{/* //icons for small devices// */}
<div className="flex mt-2 pl-2 mb-8 lg:hidden">
<AiOutlineHeart className="w-8 h-8 text-gray-600" />
<AiOutlinePlus className="w-8 h-8 ml-2 text-gray-600 " />
<button className="w-40 border ml-auto mr-4">Download</button>
</div>
</div>
))}
</div>
</InfiniteScroll>
);
};
export default Gallery;
'''

How set cards in a row using react bootstrap

I want to add card using react-bootstrap in a project. I used Grid and CardDeck option from react-bootstrap. But all cards comes in a column (like this). But I want this cards comes with side by side, not in row.(I want my output like this image).
Here the code for card section
import Card from 'react-bootstrap/Card';
const Course = (props) => {
const {title, price,details,img} = props;
return (
<div>
<div className="col-md-4 col-12 mt-5 mx-auto">
<Card>
<Card.Img variant="top" src={img} />
<Card.Body>
<Card.Title>{title}</Card.Title>
<Card.Title>{price}</Card.Title>
<Card.Text>
{
details
}
</Card.Text>
</Card.Body>
</Card>
</div>
</div>
);
};
export default Course;
Where I pass the value
import React from "react";
import fakeData from "../FakedData/FakeData";
import Course from "../Course/Course";
import CardDeck from 'react-bootstrap/CardDeck';
const Home = () => {
return (
<div>
<div className="container">
<div className="row">
<CardDeck>
{fakeData.map((data) => {
return (
<Course
key={data.id}
title={data.title}
price={data.price}
details={data.details}
img={data.img}
/>
);
})}
</CardDeck>
</div>
</div>
</div>
);
};
export default Home;
I don't try this, it's the old way with modulo, should work, but not responsive
const Home = () => {
const numInRow = 4;
return (
<div>
<div className="container">
<div class="d-flex justify-content-center"> // <---- div first row
{fakeData.map((data, idx) => { //<--- note the idx
return (
<Course
key={data.id}
title={data.title}
price={data.price}
details={data.details}
img={data.img}
/>
{idx % numInRow === 0 && </div><div class="d-flex justify-content-center">} // <--- use modulo to close row and open a new one
);
})}
</div> //<-- div last row
</div>
</div>
);
};

Resources