Two Fixed Navbars in React JS - reactjs

I have a Navbar which is already fixed to Top and looks something like this:
Now I want to add one more Navigation on top of this and it should look something like this:
The NavBars should be fixed to the top and first one should be slightly smaller in height than the second one.
The code that I am currently using right now is:
<Navbar variant="light" fixed="top" expand="lg" className="pt-4 pb-4">
<Container>
<Navbar.Brand href="/"><Image src={logo}></Image></Navbar.Brand>
<Navbar.Toggle aria-controls="basic-navbar-nav" />
<Navbar.Collapse id="basic-navbar-nav">
<Nav className="mr-auto">
<Nav.Link as={Link} to="/" className="ml-xl-4">Home</Nav.Link>
<Nav.Link className="ml-xl-4">Shop</Nav.Link>
<Nav.Link className="ml-xl-4">Sale</Nav.Link>
</Nav>
<Form inline>
<FormControl type="text" placeholder="Search" className="mr-sm-5" />
</Form>
<Nav.Link as={Link} to="/"><Image src={accountIcon}></Image></Nav.Link>
<Nav.Link as={Link} to="/cart" className="pr-0"><Image src={cartIcon}></Image></Nav.Link>
</Navbar.Collapse>
</Container>
</Navbar>
I am using FontAwesome, StyledIcons, StyledComponents and ReactBootstrap. Now I am unable to add another NavBar to top of this existing one. I tried to create another Nav inside the Container, but it is failing. Please guide me in aligning the two Navbars.

One the reasons I moved away from UI libraries is that they can be rather limiting in what you can do in terms of appearance customization. I often find that the more customized the look, the more CSS/Style overrides I have write. Some components will have completely different layouts and different classes for the same component, which means more CSS overrides! As such, this back and forth struggle is one the main reasons why I'd highly recommend utilizing the power of CSS-in-JS (like #emotion or styled-components to name a few).
Nevertheless, here's a working demo:
or
Preview: https://7m0hn.csb.app/
I've used Typescript instead of plain Javascript because VSCode allows you to hover over the component to view a JSDoc description (you may need to scroll down to view the description within dialog). Holding ctrl, while mouse left-clicking on the component, opens a preview within the same tab!
The alternative approach is just to manually add classNames to the ReactBootstrap components and apply CSS overrides. In this case, the bottom bar would be:
position: fixed; // locks it to screen
top: 30px; // at this position (factoring in the height of the top bar)
But again, this won't be as flexible as writing your own reusable components. You may find yourself creating many classes to style the same component for different pages/screen layouts/themes (like this DOM versus this DOM; or heck, even compared to this DOM which just uses a UI library sparingly).
Fixed/index.ts
import styled from "#emotion/styled";
/**
* The Fixed component is a custom styled component to mainly adjust related 'fixed: position" CSS properties.
*
* #param background - sets 'background' CSS property (default: "transparent").
* #param bottom - sets 'bottom' CSS property (default: undefined).
* #param height - sets 'height' CSS property (default: "auto").
* #param left - sets 'left' CSS property (default: undefined).
* #param padding - sets 'padding' CSS property (default: "0px").
* #param right - sets 'right' CSS property (default: undefined).
* #param top - sets 'top' CSS property (default: undefined).
* #param width - sets 'width' CSS property (default: "100%").
*/
const Fixed = styled.div<{
background?: string;
bottom?: string;
height?: string;
left?: string;
padding?: string;
right?: string;
top?: string;
width?: string;
}>`
position: fixed;
display: flex;
align-items: center;
width: 100%;
background: ${({ background }) => background || "transparent"};
border-bottom: 2px solid #ccc;
height: ${({ height }) => height || "auto"};
padding: ${({ padding }) => padding || "0px"};
top: ${({ top }) => top};
right: ${({ right }) => right};
bottom: ${({ bottom }) => bottom};
left: ${({ left }) => left};
width: ${({ width }) => width || "100%"};
`;
export default Fixed;
Flex/index.ts
import styled from "#emotion/styled";
/**
* The Flex component is a custom styled component to mainly set 'flex' CSS properties.
*
* #param align - sets 'align-items' CSS property (default: "stretch").
* #param justify - sets 'justify-content' CSS property (default: "flex-start").
* #param padding - sets 'padding' CSS property (default: "0px").
* #param width - sets 'width' CSS property (default: "100%").
*/
const Flex = styled.div<{
align?:
| "stretch"
| "center"
| "flex-start"
| "flex-end"
| "baseline"
| "initial"
| "inherit";
justify?:
| "flex-start"
| "flex-end"
| "center"
| "space-between"
| "space-around"
| "space-evenly";
padding?: string;
width?: string;
}>`
display: flex;
justify-content: ${({ justify }) => justify || "flex-start"};
align-items: ${({ align }) => align || "stretch"};
padding: ${({ padding }) => padding || "0px"};
width: ${({ width }) => width || "100%"};
`;
export default Flex;
Navbar/index.tsx
import * as React from "react";
import Nav from "react-bootstrap/Nav";
import NavDropdown from "react-bootstrap/NavDropdown";
import Navbar from "react-bootstrap/Navbar";
import Form from "react-bootstrap/Form";
import FormControl from "react-bootstrap/FormControl";
import { IoPersonOutline } from "react-icons/io5";
import { GiShoppingCart } from "react-icons/gi";
import Fixed from "../Fixed";
import Flex from "../Flex";
export type eventKey = string | null;
const TopNavBar = () => {
const [language, setLanguage] = React.useState<eventKey>("DE");
const [currency, SetCurrency] = React.useState<eventKey>("€ EUR");
const handleLanguageChange = React.useCallback((eventKey: eventKey) => {
setLanguage(eventKey);
}, []);
const handleCurrencyChange = React.useCallback((eventKey: eventKey) => {
SetCurrency(eventKey);
}, []);
return (
<>
<Navbar className="navbar-top" fixed="top">
<Flex justify="flex-end" padding="0 20px 0 0">
<NavDropdown
onSelect={handleLanguageChange}
alignRight
title={language}
id="basic-nav-dropdown"
>
<NavDropdown.Item eventKey="EN">EN</NavDropdown.Item>
<NavDropdown.Item eventKey="ES">ES</NavDropdown.Item>
<NavDropdown.Item eventKey="DE">DE</NavDropdown.Item>
<NavDropdown.Item eventKey="JP">JP</NavDropdown.Item>
</NavDropdown>
<NavDropdown
onSelect={handleCurrencyChange}
alignRight
title={currency}
id="basic-nav-dropdown"
>
<NavDropdown.Item eventKey="€ EUR">€ EUR</NavDropdown.Item>
<NavDropdown.Item eventKey="£ GBP">£ GBP</NavDropdown.Item>
<NavDropdown.Item eventKey="¥ JPY">¥ JPY</NavDropdown.Item>
<NavDropdown.Item eventKey="$ USD">$ USD</NavDropdown.Item>
</NavDropdown>
</Flex>
</Navbar>
<Fixed background="#fff" padding="5px 60px 0 20px" top="30px">
<Flex justify="flex-start">
<Navbar.Brand href="/">Brand</Navbar.Brand>
</Flex>
<Flex justify="center">
<Form inline>
<FormControl
type="text"
placeholder="Search"
className="search-box"
/>
</Form>
</Flex>
<Flex justify="flex-end">
<Nav.Link>
<IoPersonOutline />
</Nav.Link>
<Nav.Link className="pr-0">
<GiShoppingCart />
</Nav.Link>
</Flex>
</Fixed>
</>
);
};
export default TopNavBar;
App.tsx
import Navbar from "./Navbar";
import "bootstrap/dist/css/bootstrap.min.css";
import "./styles.css";
const App = () => (
<div className="app">
<Navbar />
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<p>
Curabitur aliquet quam id dui posuere blandit. Nulla porttitor accumsan
tincidunt. Nulla porttitor accumsan tincidunt. Curabitur arcu erat,
accumsan id imperdiet et, porttitor at sem. Vestibulum ante ipsum primis
in faucibus orci luctus et ultrices posuere cubilia Curae; Donec velit
neque, auctor sit amet aliquam vel, ullamcorper sit amet ligula.
Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere
cubilia Curae; Donec velit neque, auctor sit amet aliquam vel, ullamcorper
sit amet ligula. Vestibulum ac diam sit amet quam vehicula elementum sed
sit amet dui. Vestibulum ante ipsum primis in faucibus orci luctus et
ultrices posuere cubilia Curae; Donec velit neque, auctor sit amet aliquam
vel, ullamcorper sit amet ligula. Cras ultricies ligula sed magna dictum
porta. Pellentesque in ipsum id orci porta dapibus.
</p>
<p>
Proin eget tortor risus. Donec sollicitudin molestie malesuada. Lorem
ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum ante ipsum
primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec
velit neque, auctor sit amet aliquam vel, ullamcorper sit amet ligula.
Curabitur aliquet quam id dui posuere blandit. Curabitur aliquet quam id
dui posuere blandit. Curabitur aliquet quam id dui posuere blandit.
Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere
cubilia Curae; Donec velit neque, auctor sit amet aliquam vel, ullamcorper
sit amet ligula. Praesent sapien massa, convallis a pellentesque nec,
egestas non nisi. Vestibulum ac diam sit amet quam vehicula elementum sed
sit amet dui.
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin eget tortor
risus. Curabitur non nulla sit amet nisl tempus convallis quis ac lectus.
Vivamus suscipit tortor eget felis porttitor volutpat. Pellentesque in
ipsum id orci porta dapibus. Cras ultricies ligula sed magna dictum porta.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque in
ipsum id orci porta dapibus. Vestibulum ante ipsum primis in faucibus orci
luctus et ultrices posuere cubilia Curae; Donec velit neque, auctor sit
amet aliquam vel, ullamcorper sit amet ligula. Praesent sapien massa,
convallis a pellentesque nec, egestas non nisi.
</p>
</div>
);
export default App;
index.tsx
import { render } from "react-dom";
import App from "./App";
render(<App />, document.getElementById("root"));
styles.css
.app {
margin-top: 120px;
font-family: sans-serif;
text-align: center;
min-height: 120vh;
}
.navbar-top {
padding: 0;
background: #dadada;
border-bottom: 2px solid #ccc;
}
.nav-link {
padding: 2px 20px;
}
.search-box {
height: 35px;
}
::-moz-focus-inner {
border: 0;
}
::-webkit-scrollbar {
display: none;
}
html,
body {
margin: 0;
padding: 0;
background: #f9f9f9;
}
*,
:after,
:before {
-ms-overflow-style: none;
scrollbar-width: none;
box-sizing: border-box;
}

Related

How can I get a background image to show using Patternfly?

I was following this guide https://www.patternfly.org/v4/components/card/react-demos using their "Horizontal split" guide to try to get the desired effect but I am unable to get the background image to display properly even though the path to the image is correct.
I have tried to put the name of the image in curly brackets the way you do for normal images and also imported it but I am still unable to get the image to display. I am unsure of how to get the image to show up for this section.
Here is the code I have so far
import { Card, CardTitle, CardBody, CardFooter, Grid, GridItem, Button } from '#patternfly/react-core';
import dog from '../images/dog.jpg';
export default function adoptionReady() {
return (
<>
<h1>Pets Ready For Adoption</h1>
<div className="container">
<section>
<article>
<br></br>
<br></br>
<Card id="card-demo-horizontal-split-example" isFlat>
<Grid md={6}>
<GridItem
style={{
minHeight: '200px',
backgroundPosition: 'center',
backgroundSize: 'cover',
backgroundImage: 'url(../images/dog.jpg)'
} }
/>
<div class="col d-flex justify-content-center">
<Card id="card-demo-horizontal-split-example" isFlat>
<Grid md={6}>
<GridItem
style={{
minHeight: '200px',
backgroundPosition: 'center',
backgroundSize: 'cover',
backgroundImage: {dog}
}}
/>
<GridItem>
<CardTitle>Headline</CardTitle>
<CardBody>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse arcu purus, lobortis nec euismod eu,
tristique ut sapien. Nullam turpis lectus, aliquet sit amet volutpat eu, semper eget quam. Maecenas in
tempus diam. Aenean interdum velit sed massa aliquet, sit amet malesuada nulla hendrerit. Aenean non
faucibus odio. Etiam non metus turpis. Praesent sollicitudin elit neque, id ullamcorper nibh faucibus eget.
</CardBody>
<CardFooter>
<Button variant="tertiary">Call to action</Button>
</CardFooter>
</GridItem>
</Grid>
</Card>
{/* <figure>
<figcaption></figcaption>
</figure> */}
</div>
</article>
</section>
</div>
<script src="https://cdn.jsdelivr.net/npm/#popperjs/core#2.11.6/dist/umd/popper.min.js" integrity="sha384-oBqDVmMz9ATKxIep9tiCxS/Z9fNfEXiDAYTujMAeBAsjFuCZSmKbSSUnQlmh/jp3" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.2.2/dist/js/bootstrap.min.js" integrity="sha384-IDwe1+LCz02ROU9k972gdyvl+AESN10+x7tBKgc9I5HFtuNz0wWnPclzo6p9vxnk" crossorigin="anonymous"></script>
<>
</></>
);
}
Here is the example code I am trying to follow this url shows the end result that I am unable to duplicate https://www.patternfly.org/v4/components/card/react-demos/horizontal-split/
I was able to resolve the issue by inputting different code that split the content between it's containers, then all I had to just is just add a regular image like normal. Still not sure why the original code would not work though.
Leaving it here in case anyone needs it in the future when using pattern fly horizontal card tutorial.
import React from 'react';
import { Card, CardTitle, CardBody, CardFooter, Grid, GridItem, Button } from '#patternfly/react-core';
CardHorizontalSplitDemo = () => {
return (
<Card id="card-demo-horizontal-split-example" isFlat>
<Grid md={6}>
<Card id="card-demo-horizontal-split-example" isFlat>
<Grid md={6}>
<Split>
<SplitItem>
<img src={dog} alt=" " />
</SplitItem>
</Split>
<GridItem>
<CardTitle>Headline</CardTitle>
<CardBody>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse arcu purus, lobortis nec euismod eu,
tristique ut sapien. Nullam turpis lectus, aliquet sit amet volutpat eu, semper eget quam. Maecenas in
tempus diam. Aenean interdum velit sed massa aliquet, sit amet malesuada nulla hendrerit. Aenean non
faucibus odio. Etiam non metus turpis. Praesent sollicitudin elit neque, id ullamcorper nibh faucibus eget.
</CardBody>
<CardFooter>
<Button variant="tertiary">Call to action</Button>
</CardFooter>
</GridItem>
</Grid>
</Card>
);
};
Example code maybe helpful
import React from 'react';
import { ImageBackground, StyleSheet } from 'react-native';
const BackgroundImage = ({ children }) => {
return (
<ImageBackground
source={require('path/to/your/image.jpg')}
style={styles.backgroundImage}
>
{children}
</ImageBackground>
);
};
const styles = StyleSheet.create({
backgroundImage: {
flex: 1,
resizeMode: 'cover',
justifyContent: 'center'
},
});
export default BackgroundImage;
You can then use this BackgroundImage component
import BackgroundImage from './BackgroundImage';
const YourComponent = () => {
return (
<BackgroundImage>
<!-- your content here -->
</BackgroundImage>
);
};
Solution was to add a split instead of a grid item for the image.
<Grid md={6}>
<Card id="card-demo-horizontal-split-example" isFlat>
<Grid md={6}>
<Split>
<SplitItem>
<img src={dog} alt=" " />
</SplitItem>
</Split>

How to fix contents overlapping tailwind and Next.js

I'm currently trying to create a portfolio website as a result of my learnings on Next.js and tailwind.
The problem that I'm facing at the moment is that I'm unable to make my application responsive on a mobile layout. As you can see the image and the texts are overlapping themselves instead of staying in place
I'm still a beginner at web development so I don't really have any idea of how to fix it after 4 frustrating hours trying to align the contents.
Here is the code that I'm trying to implement, any ideas?
import React from 'react'
import { motion } from "framer-motion";
type Props = {}
export default function About({}: Props) {
return (
<motion.div
initial={{ opacity: 0 }}
transition={{ duration: 1.5 }}
whileInView={{ opacity: 1 }}
className='flex flex-col relative h-screen text-center md:text-left md:flex-row max-w-7xl px-10 justify-evenly mx-auto items-center'>
<h3 className='absolute top-24 uppercase tracking-[20px] text-gray-500 text-2xl'>
About
</h3>
<motion.img
initial={{
x: -200,
opacity: 0
}}
transition={{ duration: 1.2 }}
whileInView={{
x: 0,
opacity: 1
}}
viewport={{ once: true }}
src='https://images.pexels.com/photos/1572878/pexels-photo-1572878.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500' alt="profile picture"
className='-mb-20 md:mb-0 flex-shrink-0 w-56 h-56 rounded-full object-cover md:rounded-lg md:w64 md:h-95 xl:w-[500px] xl:h-[600px]'
/>
<div className='space-y-10 px-0 md:px-10'>
<h4 className='text-4xl font-semibold'>
Here is a little background
</h4>
<p className='text-base'>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi vel libero
nisi. Cras vel dignissim diam. Etiam varius enim sed libero suscipit
sagittis. Suspendisse varius, mi eu tempor porttitor, ex risus molestie
purus, vitae sagittis mi nisl et justo. Fusce fermentum vitae orci at
blandit. Nunc molestie est non metus porta pharetra. Nunc molestie
pretium felis iaculis faucibus. Sed pretium venenatis facilisis.
Vivamus vel varius velit. Nullam id odio vitae ligula efficitur
semper et nec enim. Duis convallis risus eget metus tristique,
pretium elementum eros pharetra. Nulla facilisi. In at mauris
id est ultrices ac
</p>
</div>
</motion.div>
)
}

Increase number when inView with useEffect and useState

I need to show a number, that starts at 0 and increases to X. This "counting" needs to happen when user's reach the number in view, like this example.
For this, I'm trying to use useEffect, useState and useInView, from react-intersection-observer.
But, in my code, my number is a bit crazy, changing from 1 to 2 only.
I've created a component that I can use many times, this way:
function NumericIndicator(props) {
const [counting, setCounting] = useState(false);
const [number, setNumber] = useState(0);
const [ref, inView] = useInView();
useEffect(() => {
setInterval(() => {
if (number < props.value) {
setNumber(number + 1);
} else {
setNumber(props.value);
}
}, 500);
}, [counting]);
useEffect(() => {
if (inView && !counting) {
setCounting(true);
}
}, [inView]);
return (
<div ref={ref}>
<h1>{number}</h1>
<p>
<small>This needs to increase from 0 to {props.value}</small>
</p>
</div>
);
}
Here's a full StackBlitz with my code
Thank you!
Try
import React from 'react';
import { useEffect, useState } from 'react';
import { useInView } from 'react-intersection-observer';
import './style.css';
export default function App() {
return (
<div>
<div style={{ minHeight: '100vh' }}>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin
convallis sagittis finibus. Maecenas mauris odio, feugiat vel orci
non, consectetur placerat turpis. Proin tincidunt ut tellus posuere
euismod. Donec id venenatis dui. Quisque ultrices dignissim ipsum ut
tempus. Praesent mollis elit ac magna laoreet tempus at a dui.
Suspendisse sed venenatis arcu, quis commodo sapien. Ut at malesuada
dui. Curabitur feugiat elementum ligula, a pellentesque tortor. Fusce
id nisl ornare, congue dui vitae, ornare ex. Class aptent taciti
sociosqu ad litora torquent per conubia nostra, per inceptos
himenaeos.
</p>
<p>
Vivamus blandit leo ac magna efficitur vulputate. Praesent vitae magna
elit. Nullam non metus nec mauris maximus tincidunt a ac velit. Aenean
elit metus, aliquet at gravida ornare, commodo gravida nisl. Cras
vestibulum lacinia erat sit amet cursus. Donec pretium enim porttitor
magna tincidunt, a venenatis sem bibendum. Aenean ornare enim et odio
pharetra iaculis. Class aptent taciti sociosqu ad litora torquent.
</p>
</div>
<div style={{ height: '50vh', backgroundColor: '#27ae60' }}>
<NumericIndicator value={10} />
</div>
<div style={{ height: '50vh', backgroundColor: '#e67e22' }}>
<NumericIndicator value={70} />
</div>
<div style={{ height: '50vh', backgroundColor: '#9b59b6' }}>
<NumericIndicator value={90} />
</div>
<div style={{ height: '50vh', backgroundColor: '#2c3e50' }}>
<NumericIndicator value={110} />
</div>
</div>
);
}
function NumericIndicator(props) {
const [number, setNumber] = useState(0);
const [ref, inView] = useInView();
useEffect(() => {
if (!inView) return () => {};
const interval = setInterval(() => {
setNumber((prev) => Math.min(prev + 1, props.value));
}, 500);
return () => clearInterval(interval);
}, [inView, props.value, number]);
return (
<div ref={ref}>
<h1>{number}</h1>
<p>
<small>This needs to increase from 0 to {props.value}</small>
</p>
</div>
);
}

how to create Top drawer with Materail ui react which start from the bottom of navbar?

actually, I am trying to create a responsive app bar using the material UI/app drawer. when I clicked the but it starts from the top of the page and makes the background dark but I want to make it start from the bottom of the app bar without making the background dark. please help me and give example using codesandbox https://codesandbox.io/s/64ulq
I trying to do this
but it shows like that
you can make a mix of multiple exemple of material ui drawer (Persistent and clipped one) and it give you something like this :
import React from 'react';
import { createStyles, Theme, makeStyles } from '#material-ui/core/styles';
import Drawer from '#material-ui/core/Drawer';
import AppBar from '#material-ui/core/AppBar';
import CssBaseline from '#material-ui/core/CssBaseline';
import Toolbar from '#material-ui/core/Toolbar';
import List from '#material-ui/core/List';
import Typography from '#material-ui/core/Typography';
import Divider from '#material-ui/core/Divider';
import ListItem from '#material-ui/core/ListItem';
import ListItemIcon from '#material-ui/core/ListItemIcon';
import ListItemText from '#material-ui/core/ListItemText';
import InboxIcon from '#material-ui/icons/MoveToInbox';
import MailIcon from '#material-ui/icons/Mail';
import IconButton from '#material-ui/core/IconButton';
import MenuIcon from '#material-ui/icons/Menu';
const drawerWidth = "100vw";
const useStyles = makeStyles((theme: Theme) =>
createStyles({
root: {
},
appBar: {
zIndex: theme.zIndex.drawer + 1,
},
drawer: {
width:"100vw",
},
drawerPaper: {
width: drawerWidth,
},
drawerContainer: {
overflow: 'auto',
},
content: {
flexGrow: 1,
padding: theme.spacing(3),
},
}),
);
export default function ClippedDrawer() {
const classes = useStyles();
const [open, setOpen] = React.useState(false);
const handleDrawerOpen = () => {
setOpen(!open);
};
return (
<div className={classes.root}>
<CssBaseline />
<AppBar position="fixed" className={classes.appBar}>
<Toolbar>
<IconButton
color="inherit"
aria-label="open drawer"
onClick={handleDrawerOpen}
edge="start"
>
<MenuIcon />
</IconButton>
<Typography variant="h6" noWrap>
Clipped drawer
</Typography>
</Toolbar>
</AppBar>
<Drawer
anchor="top"
className={classes.drawer}
variant="persistent"
open={open}
classes={{
paper: classes.drawerPaper,
}}
>
<Toolbar />
<div className={classes.drawerContainer}>
<List>
{['Inbox', 'Starred', 'Send email', 'Drafts'].map((text, index) => (
<ListItem button key={text}>
<ListItemIcon>{index % 2 === 0 ? <InboxIcon /> : <MailIcon />}</ListItemIcon>
<ListItemText primary={text} />
</ListItem>
))}
</List>
<Divider />
<List>
{['All mail', 'Trash', 'Spam'].map((text, index) => (
<ListItem button key={text}>
<ListItemIcon>{index % 2 === 0 ? <InboxIcon /> : <MailIcon />}</ListItemIcon>
<ListItemText primary={text} />
</ListItem>
))}
</List>
</div>
</Drawer>
<main className={classes.content}>
<Toolbar />
<Typography paragraph>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt
ut labore et dolore magna aliqua. Rhoncus dolor purus non enim praesent elementum
facilisis leo vel. Risus at ultrices mi tempus imperdiet. Semper risus in hendrerit
gravida rutrum quisque non tellus. Convallis convallis tellus id interdum velit laoreet id
donec ultrices. Odio morbi quis commodo odio aenean sed adipiscing. Amet nisl suscipit
adipiscing bibendum est ultricies integer quis. Cursus euismod quis viverra nibh cras.
Metus vulputate eu scelerisque felis imperdiet proin fermentum leo. Mauris commodo quis
imperdiet massa tincidunt. Cras tincidunt lobortis feugiat vivamus at augue. At augue eget
arcu dictum varius duis at consectetur lorem. Velit sed ullamcorper morbi tincidunt. Lorem
donec massa sapien faucibus et molestie ac.
</Typography>
<Typography paragraph>
Consequat mauris nunc congue nisi vitae suscipit. Fringilla est ullamcorper eget nulla
facilisi etiam dignissim diam. Pulvinar elementum integer enim neque volutpat ac
tincidunt. Ornare suspendisse sed nisi lacus sed viverra tellus. Purus sit amet volutpat
consequat mauris. Elementum eu facilisis sed odio morbi. Euismod lacinia at quis risus sed
vulputate odio. Morbi tincidunt ornare massa eget egestas purus viverra accumsan in. In
hendrerit gravida rutrum quisque non tellus orci ac. Pellentesque nec nam aliquam sem et
tortor. Habitant morbi tristique senectus et. Adipiscing elit duis tristique sollicitudin
nibh sit. Ornare aenean euismod elementum nisi quis eleifend. Commodo viverra maecenas
accumsan lacus vel facilisis. Nulla posuere sollicitudin aliquam ultrices sagittis orci a.
</Typography>
</main>
</div>
);
}
code sandbox

MUI: how to show tooltip component over selected text?

Like on medium:
Tooltip from matetial-ui react framework.
some ideas:
wrap selected text with <span> and use that element as reference node
of tooltip (over complicated I guess)
create tooltip w/o child and specify
absolute position based on selected text
any other ideas?
The simplest: https://www.w3schools.com/css/css_tooltip.asp
The more effective: https://chrisbracco.com/a-simple-css-tooltip/
:)
Medium.com uses popper.js. I found this out by searching the tag parameters in Medium's HTML.
<div class="bz fx mc yw"
style=
"position: absolute; inset: auto auto 0px 0px; transform: translate(692px, 1233px);"
data-popper-reference-hidden="false"
data-popper-escaped="false"
data-popper-placement="top">
https://popper.js.org/
It does the thing where it repositons the popup if you scroll, I checked.
I used the popper component instead of tooltip component link: https://mui.com/material-ui/react-popper/#virtual-element
demo: https://codesandbox.io/s/iztu66?file=/demo.js
code
import * as React from 'react';
import Popper from '#mui/material/Popper';
import Typography from '#mui/material/Typography';
import Fade from '#mui/material/Fade';
import Paper from '#mui/material/Paper';
export default function VirtualElementPopper() {
const [open, setOpen] = React.useState(false);
const [anchorEl, setAnchorEl] = React.useState(null);
const handleClose = () => {
setOpen(false);
};
const handleMouseUp = () => {
const selection = window.getSelection();
// Resets when the selection has a length of 0
if (!selection || selection.anchorOffset === selection.focusOffset) {
handleClose();
return;
}
const getBoundingClientRect = () =>
selection.getRangeAt(0).getBoundingClientRect();
setOpen(true);
setAnchorEl({
getBoundingClientRect,
});
};
const id = open ? 'virtual-element-popper' : undefined;
return (
<div onMouseLeave={handleClose}>
<Typography aria-describedby={id} onMouseUp={handleMouseUp}>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam ipsum purus,
bibendum sit amet vulputate eget, porta semper ligula. Donec bibendum
vulputate erat, ac fringilla mi finibus nec. Donec ac dolor sed dolor
porttitor blandit vel vel purus. Fusce vel malesuada ligula. Nam quis
vehicula ante, eu finibus est. Proin ullamcorper fermentum orci, quis finibus
massa. Nunc lobortis, massa ut rutrum ultrices, metus metus finibus ex, sit
amet facilisis neque enim sed neque. Quisque accumsan metus vel maximus
consequat. Suspendisse lacinia tellus a libero volutpat maximus.
</Typography>
<Popper
id={id}
open={open}
anchorEl={anchorEl}
transition
placement="bottom-start"
>
{({ TransitionProps }) => (
<Fade {...TransitionProps} timeout={350}>
<Paper>
<Typography sx={{ p: 2 }}>The content of the Popper.</Typography>
</Paper>
</Fade>
)}
</Popper>
</div>
);
}
You can add your own buttons after fade component or inside in paper component.

Resources