I have a navigation bar for my webapp with the following css setup:
.navigation {
background: white;
display: flex;
height: 5em;
align-items: center;
padding: 0px 2em;
color: blue;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.075em;
border-bottom: 1px solid #E6E6E6;}
My issue is on mobile, my tabs in the navigation bar get all squeezed together. Is there a way in React that I can detect the width of the page and collapse all my navigation tabs into a dropdown menu? Or is this a CSS thing?
You could handle this in CSS, using proper media queries.
But if you prefer to do it with React, here is how you can implement it, listening to the window "resize" event:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
layoutMode: this.getLayoutMode(),
};
this.onResize = this.onResize.bind(this);
}
componentDidMount() {
window.addEventListener('resize', this.onResize);
}
componentWillUnmount() {
window.removeEventListener('resize', this.onResize);
}
onResize() {
this.setState({
layoutMode: this.getLayoutMode(),
});
}
getLayoutMode() {
return window.innerWidth > 1000 ?
'desktop'
: 'mobile';
}
render() {
return this.state.layoutMode === 'desktop' ? (
<NavigationBar />
) : (
<DropdownMenu />
);
}
}
Seriously, your best option is css. Let react focus on the structure of your DOM and on the interaction. Let css take care of styling.
So you can keep your react code simple like this:
render() {
var myMenu = ['Home','Settings','About us', 'Other stuff'];
return (
<div>
<button className='hamburger'>m</button>
<ul className='menu'>
{myMenu.map(item => {
return <MenuItem key={item} text={item}/>
})}
</ul>
</div>
);
}
And do the styling stuff in css (code below with Sass):
ul.menu
position: absolute
display: flex
flex-direction: row
width: 100%
li.menu-item
flex: 1 0 auto
padding: 10px
margin: 2px
background-color: grey
text-align: center
li.menu-item:hover
background-color: blue
button.hamburger
display: none
padding: 10px
margin: 2px
background-color: grey
#media screen and (max-width : 760px)
ul.menu
flex-direction: column
display: none
li.menu-item
background-color: orange
button.hamburger
display: block
position: absolute
button.hamburger:focus + ul.menu
display: flex
You can find a working demo in codepen here.
If you want to render a drop-down menu on mobile, here's one strategy:
Listen for media query changes in React: http://krasimirtsonev.com/blog/article/Using-media-queries-in-JavaScript-AbsurdJS-edition.
Use that listener to update this.state on the component (ex: this.state.isMobile).
Render different Navigation components based on the media query conditional (ex: this.state.isMobile ? <Navigation type="mobile" /> : <Navigation type="desktop" />).
Related
I am creating a basic nav bar and I want to change it based on screen size. Once it hits 600px i'd like to hide the links and display a clickable nav button that will expand those options.
After console logging my list Elements I found that the className was given this 'Nav_floatLeft__H1YZ8'. So based on that finding, my code is as follows. However, my navigation does not display any changes when clicking the button.
I'm sure React has a better way of handling this situation, but I'm fairly new to it. Should I be using some kind of state/effect hook?
Nav:
const openCloseMenu = () => {
console.log(document.getElementsByClassName(styles.floatLeft).className);
let elements = document.getElementsByClassName(styles.floatLeft);
if (elements.className === "Nav_floatLeft__H1YZ8"){
alert("Changed to: Menu Bar Expanded");
elements.className = styles.menuBarExpanded;
}
else {
alert("Changed Back to: Float Left")
elements.className = styles.floatLeft;
}
}
return (
<div className={styles.topNav}>
<nav>
<ul className={styles.inlineListItem}>
<li className={styles.floatLeft}>
<Link href="/">
<a>Home</a>
</Link>
</li>
<li className={styles.floatLeft}>
<Link href="/search">
<a>Search</a>
</Link>
</li>
<li className={styles.menuBar}>
<button onClick={openCloseMenu}>Expand Nav</button>
</li>
</ul>
</nav>
</div>
)
CSS:
.inlineListItem{
display: inline;
list-style: none;
}
.floatLeft{
float: left;
margin: 1rem;
padding-left: 1rem;
text-align: center;
color: white;
}
.floatRight{
display: inline;
float: right;
color: white;
margin: 1rem;
padding-right: 2rem;
}
.menuBar{
display: none;
float: left;
margin: 1rem;
padding-left: 1rem;
text-align: center;
color: white;
}
.menuBarExpanded{
display: block;
}
#media screen and (max-width: 600px) {
.menuBar{
display: block;
}
.floatLeft{
display: none;
}
.floatRight{
display: none;
}
}
ways are there to solve this problem.
You can use material UI. To detect the breakpoint.
Like for you case. If want to detect 600px.
you can do something like that ---
const themeBreakpoint = theme.breakpoint.down('600px) // themeBreakpoint will be true under 600px.
using this flag you can change state and show what ever you want by using condition rendering.
Second Problem --
you can change any state based on onClick event.
like --
const[clicked,setclicked] = useState(false)
const handleClick = (e) =>{
setclicked(true)
}
now when you make that clicked flag true, You change you css class based on that flag.
You could implement an useState hook:
import { useState } from "react";
const YourComponent = () => {
const [cliked, setClicked] = useState(false);
return (
<YourNavbar className={clicked ? "display" : "hide"} />
....
<button onClick={() => setClicked(current => !current)}>Expand Nav</button>
....
)
}
And on css, you can establish the class display with the actual attributes of the navbar, and a hidden (display: none)
This will check if the navbar button has been clicked (set to true), and on the conditional class, if its true, then it will display the navbar through the "display" class, if the button is clicked again, clicked will be false and the class for the navbar will be "hidden".
Remember to delegate this classnames to the item only when the navbar is below 600px with #media
I'm using React and trying to fetch some of my anime into the home banner using Swiper
I don't know why when I refresh my page, it'll only render at half of the swiper.
Here's how it display:
However, if I press the next or back button, it'll display normally again.
Here's my code in my Home Component:
import { useState, useEffect } from "react"
import ReactHlsPlayer from 'react-hls-player';
import './home.css'
import { supabase } from '../../supabaseClient'
import { Swiper, SwiperSlide } from 'swiper/react'
import SwiperCore, { Pagination,Navigation } from 'swiper';
import 'swiper/css'
SwiperCore.use([Pagination,Navigation]);
function Home(){
useEffect(async ()=>{
fetchAnime()
}, [])
const [animeDetail, setAnimeDetail] = useState([])
async function fetchAnime() {
const { data } = await supabase
.from ('anime')
.select ()
setAnimeDetail(data)
}
return (
<>
<div className="spacer">
</div>
<div className="home-section">
<h2>Home Page</h2>
<Swiper
centeredSlides={true}
slidesPerView={7}
spaceBetween={10}
loop={true}
pagination={false}
navigation={true} className="mySwiper">
{animeDetail.map((element, i)=>
(
<SwiperSlide key = {i}><img src={element.anime_image}/></SwiperSlide>
)
)}
</Swiper>
</div>
</>
)
}
export default Home
And here's my Home CSS, sorry if it's a bit messy, I'm still trying it here and there, but I'm stuck.
.swiper {
width: 100%;
height: 100%;
margin-left: auto;
margin-right: auto;
}
.swiper-wrapper{
width: 100%
}
.swiper-slide {
text-align: center;
font-size: 18px;
display: flex;
justify-content: center;
align-items: center;
max-width: 280px;
}
.swiper-slide img {
display: block;
box-sizing: border-box;
border: none;
max-height: 350px;
min-height: 350px;
-o-object-fit: cover;
object-fit: cover;
transition: all .3s ease;
opacity: 0.5
}
.swiper-slide-active {
transform: scale(1.2);
z-index: 2
}
.swiper-slide-active img{
transition: all .3 ease;
opacity: 1
}
And if someone figures it out, please help me a bit, I tried to whenever the item in the middle is in active, it'll pop out bigger, but I can't do it with transform: scale(number) - I have tried it (It does get bigger when it's active but it doesn't display bigger at the height, I haven't figured it out some ways at the moment)
you have to set the initialSlide prop on the Swiper element to an index of the slide in the middle. so that the slider starts from there.
Also in this case, you can set the centeredSlides prop to true as the active slide remains in the middle.
Here's a possible fix for your issue and for everyone else that comes here looking for answers.
Use conditional rendering of the Swiper component, something like this:
{animeDetail.length>0 && <Swiper
centeredSlides={true}
slidesPerView={7}
spaceBetween={10}
loop={true}
pagination={false}
navigation={true} className="mySwiper">
{animeDetail.map((element, i)=>
(
<SwiperSlide key = {i}><img src={element.anime_image}/></SwiperSlide>
)
)}
</Swiper>}
I want to create pages which can override over another pages in React. Like see for an example here in Youtube: https://youtu.be/n5kr99DAjDk?t=441. The 'Post' page is opened with full height and a 'Back' button. This was easily possible in React Native. How could it be done in React for web.
Below is the code for reference:
App.js
const Routing = () => {
return (
<Router>
<TopNavbar />
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/newPage" component={NewPage} />
</Switch>
<BottomNavbar />
</Router>
);
};
Home.js
const Home = () => {
return (
<div style={{ marginTop: "80px", position:'relative' }}>
<h2>Home Page</h2>
<Link to="/newPage">
<button>Click Here</button>
</Link>
</div>
);
};
export default Home;
NewPage.js
const NewPage = () => {
return (
<div className="newPageCSS">
<h2>New Page</h2>
</div>
);
};
export default NewPage;
NewPage.css
.newPageCSS {
margin-top: 80px;
position: absolute;
top:0;
left: 0;
}
I have tried position:absolute in NewPage but, no use. What could be best possible solution?
Please have a look at the given below codesandbox link for clarity of code.
Here is the codesandbox link: https://codesandbox.io/s/react-material-forked-9dodd
It sounds like you'd like your new page component to take up all the room of the page except for top and bottom navigation.
The solution is entirely CSS, however you'll need to tinker with styles to get margins/padding correct. It looks like you're using a UI library which can clash with your style sheet.
Here are the changes:
Update your main container to use flexbox instead of trying to control for top/bottom navs with pixels
#root {
display: flex;
min-height: 100vh;
flex-direction: column;
}
Then, get your new page component to expand by adding a flex 1. Added red border to easily visualize change.
.newPageCSS {
margin-top: 80px;
border: 2px solid red;
flex: 1;
}
Update your home page so bottom nav sticks to bottom and you can scroll home content
.homePageCSS {
margin-top: 80px;
max-height: 50%;
/* position: relative; */
flex: 1;
max-height: 70vh;
overflow: auto;
}
Position fixed is now unnecessary for bottom nav
.makeStyles-gridList-2 {
width: 100%;
border: 1px solid grey;
/* bottom: 0px; */
/* position: fixed; */
padding: 0;
flex-wrap: nowrap;
background: white;
}
I have 2 boxes: Panel and Sidebar, in a flexbox, with flex-direction: row and justify-content: space-between I am able to horizontally align them side by side with a gap in the middle.
Now I'd like to fix the right Sidebar position, i.e. when scrolling down, the Sidebar should always stay on top of the screen, regardless of the location of Panel. How can I do it with CSS?
Working example here: https://codesandbox.io/s/gallant-saha-zgmnw
Code here:
App.js:
import React from "react";
import "./App.scss";
import Panel from "./Panel";
import Sidebar from "./Sidebar";
export default function App() {
return (
<div className="App">
<Panel />
<Sidebar />
</div>
);
}
App.scss:
.App {
width: 1100px;
font-family: sans-serif;
text-align: center;
display: flex;
flex-direction: row;
justify-content: space-between;
}
Panel.js:
import React from "react";
import "./Panel.scss";
const Panel = () => {
return (
<>
<div className="panel">The main panel</div>
</>
);
};
export default Panel;
Sidebar.js:
import React from "react";
import "./Sidebar.scss";
const Sidebar = () => {
return (
<>
<div className="sidebar">The sidebar</div>
</>
);
};
export default Sidebar;
I modified your siderbar css.
I used position fixed as this will make the sidebar fixed in the viewport so as you scroll it will remain static.
.sidebar {
position: fixed; /* add this */
width: 200px;
height: 200px;
text-align: center;
border: 1px black solid;
left: 906px /* add this */
}
This produces the desired effect. Tested and works. Apologies, I have updated my answer.
add this css to .sidebar
position:fixed;
right: 10px;
also, you can add:
top: -- px
if you have Navbar.
I am making a few separate pages which each containing a modal (or two). I have made a css styling sheet to make JUST ONE of these full screen I would like the rest to stay the same size.
However this has affected all of my modals not just one.
My first course of action was to remove this modal (and the css sheet)from the folder it was contained within in a hope that the css style sheet would no longer affect the other modals now it is outside of the folder. This did not work.
So essentially I feel as if inline styling in this instance is the best course of action.However I am not sure how to do the styling for this specific modal.
I am here asking for any advice on how to either tackle the styling sheet issue or how to make this work through inline styling.
Here is my folder structure as you can see adminviewWorkstatioModal is in a separate folder along with viewWorkstationModal.css however the style of this still affects the rest of the files in the picture.
Example of one of the modals(template only)
class DisplayAddQuestion extends React.Component {
constructor(props) {
super(props);
this.handleClose = this.handleClose.bind(this);
this.handleShow = this.handleShow.bind(this);
this.handleRefresh = this.handleRefresh.bind(this);
this.state = {
show: false,
show1: false
};
}
handleClose() {
this.setState({
show: false,
show1: false
});
}
handleShow() {
this.setState({
show: true
});
}
handleRefresh() {
window.location.reload();
}
render() {
// console.log(this.state);
return (
<div className="header-container">
<button
className="btn btn-primary"
style={{ float: "right" }}
onClick={this.handleShow}
>
+
</button>
<Modal
className="modal-container custom-map-modal"
show={this.state.show}
onHide={this.handleClose}
animation={true}
>
<Modal.Header closeButton></Modal.Header>
<Modal.Body></Modal.Body>
</Modal>
</div>
);
}
}
And finally the css sheet
.modal-dialog {
width: 100% !important;
height: 100% !important;
margin: 0 !important;
padding: 0 !important;
max-width: none !important;
}
.modal-content {
height: auto !important;
min-height: 100% !important;
border-radius: 0 !important;
background-color: #ececec !important;
}
.modal-header {
border-bottom: 1px solid #9ea2a2 !important;
}
.modal-footer {
border-top: 1px solid #9ea2a2 !important;
}
Thanks in advance !!