MUI: Overlap text over an image? - css

I'm trying to make half of the text overflow (overlay) with the image on the right.
How do I achieve this within a Grid item? I tried using position "absolute", "relative" and "z-index", but it doesn't seem to work in the context of MUI. What is the best approach? Thank you in advance.
code
import React, { useState } from 'react';
import './../App.css';
import {Grid, Typography, Paper, useMediaQuery, useTheme, Container, CardMedia} from '#material-ui/core';
import {makeStyles} from '#material-ui/core/styles';
const useStyles = makeStyles((theme) => ({
imgSpacing: {
marginLeft: '20px'
},
holder: {
display: 'flex'
},
holderText: {
},
holderImg: {
flexGrow: '1'
}
}))
function Homepage() {
const classes = useStyles();
return (
<div>
<section>
<Container maxWidth={false} className={classes.img}>
<Grid item xs={12} container>
<Grid item xs={2} />
<Grid item xs={5}>
<div className={classes.holder}>
<div className={classes.holderText}>
<Typography >
<h1>
Lorem ipsum dolor sit amet.
</h1>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
</p>
</Typography>
</div>
<div className={classes.holderImg}>
<Paper >
<CardMedia
component="img"
image={require(`../images/LA_night_car.jpg`)}
/>
</Paper>
</div>
</div>
</Grid>
<Grid item xs={2}>
<Paper className={classes.imgSpacing}>
<CardMedia
component="img"
image={require(`../images/skater.jpg`)}
/>
</Paper>
</Grid>
<Grid item xs={3} />
</Grid>
</Container>
</section>
</div>
);
}
export default Homepage;
image for reference

An overflown text over an image is no longer a text nor an image, its a composite component/container that should have its own name - say HomepageHeadliner (you should definitely try to use a name more specific to your domain if you can though!).
Put them into said container and use the reasoning you have with absolute positioning. No z-index should be required if the text comes before the image in the DOM tree.

You should use a box item, use the property background and inside the box add any typography text you want like this
<Box
sx={{
background: `url('/img/baner.svg')`,
backgroundSize: "733px 240px",
height: 240,
width: "auto",
}}
>
<Typography
variant="inherit"
fontSize="110%"
>
Here goes the text
</Typography>
</Box>

Related

Issues with CSS transitions on Next.js project

I'm working on a project in Next.js (React) for the first time. It's a static site (only frontend).
Somehow I run into lots of problems related to the CSS transitions and I can't catch what am I missing.
When using some ready components, for example Modal from react-bootstrap, the transition seems to be working on Modal show, but not on hide. Transitions from Accordion, from the same module, work fine, but didn't work from other Accordion component I tried before that.
I will put some code here, but I have a filling, that there is some fundamental css/js related topic that I don't understand fully, but my searches didn't bring me the answer yet.
Here is the sample of the component, the related CSS is the default bootstrap-css (for the sake of simplicity):
Nav.tsx
import Link from 'next/link'
import navStyles from '../styles/Nav.module.css'
import homeStyles from "../styles/Home.module.css"
import {useState} from "react";
import Modal from "react-bootstrap/cjs/Modal"
import Button from "react-bootstrap/cjs/Button";
const MyVerticallyCenteredModal = (props) => {
return (
<Modal
{...props}
size="lg"
aria-labelledby="contained-modal-title-vcenter"
centered
>
<Modal.Header>
<Button onClick={props.onHide}>X</Button>
</Modal.Header>
<Modal.Body>
<p style={{color: "white"}}>Lorem ipsum dolor sit amet, consectetur adipisicing
elit. Aliquid at consequuntur cum ducimus enim fuga hic laudantium magni
maiores, molestias nesciunt nihil nisi nostrum pariatur perspiciatis rem rerum
suscipit, unde?</p>
</Modal.Body>
<Modal.Footer>
<Button onClick={props.onHide}>Close</Button>
</Modal.Footer>
</Modal>
);
}
const Nav = () => {
const [modalShow, setModalShow] = useState(false);
const NavComp = () => {
return (
<>
<div className={navStyles.wrapper}>
<div className={`${homeStyles.home} ${homeStyles.mobile}`}>
<div className={navStyles.footer}>
<button
className={`${navStyles.footerBtn}`}
onClick={() => setModalShow(true)}
style={{borderLeft: "1px rgba(70,70,70,0.5) solid"}}
>
Contact
</button>
<MyVerticallyCenteredModal
show={modalShow}
onHide={() => setModalShow(false)}
/>
</div>
</div>
</div>
</>
)
}
return (
<nav className={navStyles.nav}>
<div className={navStyles.container}>
<div className={navStyles.logo}>
<Link href='/'>
<div>
<p className={navStyles.kaveem}>KAVEEM</p>
</div>
</Link>
</div>
<NavComp/>
</div>
</nav>
);
};
export default Nav;

How to make React Material-UI Accordion fill entire height?

I have 2 Material-ui Accordions which I want to expand to their full height in the following way:
Both of them collapsed.
One collapsed (take the maximum height possible)
Both expanded (each take 50% of the full height)
Can I achieve this with the following code simply with CSS? (thought it should be possible with flex-grow and flex-direction:column but I can't get it to work.
https://codesandbox.io/s/upbeat-tesla-uchsb?file=/accordionFullHeight
import React from 'react';
import { makeStyles } from '#material-ui/core/styles';
import Accordion from '#material-ui/core/Accordion';
import AccordionSummary from '#material-ui/core/AccordionSummary';
import AccordionDetails from '#material-ui/core/AccordionDetails';
import Typography from '#material-ui/core/Typography';
import ExpandMoreIcon from '#material-ui/icons/ExpandMore';
const useStyles = makeStyles((theme) => ({
root: {
width: '100%',
background: 'green',
height: '90vh'
},
heading: {
fontSize: theme.typography.pxToRem(15),
fontWeight: theme.typography.fontWeightRegular,
},
}));
export default function SimpleAccordion() {
const classes = useStyles();
return (
<div className={classes.root}>
<Accordion>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
aria-controls="panel1a-content"
id="panel1a-header"
>
<Typography className={classes.heading}>Accordion 1</Typography>
</AccordionSummary>
<AccordionDetails>
<Typography>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex,
sit amet blandit leo lobortis eget.
</Typography>
</AccordionDetails>
</Accordion>
<Accordion>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
aria-controls="panel2a-content"
id="panel2a-header"
>
<Typography className={classes.heading}>Accordion 2</Typography>
</AccordionSummary>
<AccordionDetails>
<Typography>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex,
sit amet blandit leo lobortis eget.
</Typography>
</AccordionDetails>
</Accordion>
</div>
);
}
Solved it using a controlled Accordion that uses flex-grow:1 only when its expanded:
https://codesandbox.io/s/upbeat-tesla-uchsb?file=/src/MyAccordion.js
import React from "react";
import { makeStyles } from "#material-ui/core/styles";
import Accordion from "#material-ui/core/Accordion";
import AccordionDetails from "#material-ui/core/AccordionDetails";
import AccordionSummary from "#material-ui/core/AccordionSummary";
import Typography from "#material-ui/core/Typography";
import ExpandMoreIcon from "#material-ui/icons/ExpandMore";
const useStyles = makeStyles((theme) => ({
root: {
width: "100%",
background: "red",
color: "blue"
},
rootExpanded: {
background: "blue",
flexGrow: 1
}
}));
export default function MyAccordion(props) {
const classes = useStyles();
const { name } = props;
const [expanded, setExpanded] = React.useState(false);
const rootClass = expanded ? classes.rootExpanded : classes.root;
const handleChange = (panel) => (event, isExpanded) => {
setExpanded(isExpanded ? panel : false);
};
return (
<Accordion
className={rootClass}
expanded={expanded === name}
onChange={handleChange(name)}
>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
aria-controls="panel1bh-content"
id={`${name}-header`}
>
<Typography className={classes.heading}>General settings</Typography>
<Typography className={classes.secondaryHeading}>
I am an accordion
</Typography>
</AccordionSummary>
<AccordionDetails>
<Typography>
Nulla facilisi. Phasellus sollicitudin nulla et quam mattis feugiat.
Aliquam eget maximus est, id dignissim quam.
</Typography>
</AccordionDetails>
</Accordion>
);
}

How to change default behavior of components from Material UI

I am using materialUI to display an Expansion Panel as shown in following code:
import React from 'react'
import ExpansionPanel from '#material-ui/core/ExpansionPanel';
import ExpansionPanelSummary from '#material-ui/core/ExpansionPanelSummary';
import ExpansionPanelDetails from '#material-ui/core/ExpansionPanelDetails';
import Typography from '#material-ui/core/Typography';
import ExpandMoreIcon from '#material-ui/icons/ExpandMore';
function ExpansionPanelDemo(props) {
const {curr} = props
return (
<div>
<ExpansionPanel id={curr.id}>
<ExpansionPanelSummary expandIcon={<ExpandMoreIcon />}>
<Typography>{curr.name}</Typography>
</ExpansionPanelSummary>
<ExpansionPanelDetails>
<Typography> {curr.content} </Typography>
</ExpansionPanelDetails>
</ExpansionPanel>
</div>
)
}
export default ExpansionPanelDemo
It works fine but by default, it displays the expand icon to the right of the screen , I want to modify this and display the icon to the left of panel.
I tried doing this using "IconButtonProps" prop given in the documentation https://material-ui.com/api/expansion-panel-summary/ and modified code as follows:
import React from 'react'
import ExpansionPanel from '#material-ui/core/ExpansionPanel';
import ExpansionPanelSummary from '#material-ui/core/ExpansionPanelSummary';
import ExpansionPanelDetails from '#material-ui/core/ExpansionPanelDetails';
import Typography from '#material-ui/core/Typography';
import ExpandMoreIcon from '#material-ui/icons/ExpandMore';
function ExpansionPanelDemo(props) {
const {curr} = props
const icon = {
float: "left"
}
return (
<div>
<ExpansionPanel id={curr.id}>
<ExpansionPanelSummary expandIcon={<ExpandMoreIcon />} IconButtonProps={icon}>
<Typography>{curr.name}</Typography>
</ExpansionPanelSummary>
<ExpansionPanelDetails>
<Typography> {curr.content} </Typography>
</ExpansionPanelDetails>
</ExpansionPanel>
</div>
)
}
export default ExpansionPanelDemo
But something is off, the code isn't working. Can someone suggest what's wrong or any other methods to display the icon to left
ExpansionPanelSummary uses a flex display around the content and expandIcon. To re-order these, you can use either the flex-direction CSS property or the order CSS property. One other change to make this look decent is to flip the edge property on the IconButton from end to start.
Here is a working example:
import React from "react";
import { withStyles, makeStyles } from "#material-ui/core/styles";
import ExpansionPanel from "#material-ui/core/ExpansionPanel";
import ExpansionPanelSummary from "#material-ui/core/ExpansionPanelSummary";
import ExpansionPanelDetails from "#material-ui/core/ExpansionPanelDetails";
import Typography from "#material-ui/core/Typography";
import ExpandMoreIcon from "#material-ui/icons/ExpandMore";
const useStyles = makeStyles(theme => ({
root: {
width: "100%"
},
heading: {
fontSize: theme.typography.pxToRem(15),
fontWeight: theme.typography.fontWeightRegular
}
}));
const FlippedOrderExpansionPanelSummary = withStyles({
root: {
flexDirection: "row-reverse"
}
})(ExpansionPanelSummary);
FlippedOrderExpansionPanelSummary.defaultProps = {
IconButtonProps: { edge: "start" }
};
export default function SimpleExpansionPanel() {
const classes = useStyles();
return (
<div className={classes.root}>
<ExpansionPanel>
<FlippedOrderExpansionPanelSummary
expandIcon={<ExpandMoreIcon />}
aria-controls="panel1a-content"
id="panel1a-header"
>
<Typography className={classes.heading}>Expansion Panel 1</Typography>
</FlippedOrderExpansionPanelSummary>
<ExpansionPanelDetails>
<Typography>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse
malesuada lacus ex, sit amet blandit leo lobortis eget.
</Typography>
</ExpansionPanelDetails>
</ExpansionPanel>
<ExpansionPanel>
<FlippedOrderExpansionPanelSummary
expandIcon={<ExpandMoreIcon />}
aria-controls="panel2a-content"
id="panel2a-header"
>
<Typography className={classes.heading}>Expansion Panel 2</Typography>
</FlippedOrderExpansionPanelSummary>
<ExpansionPanelDetails>
<Typography>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse
malesuada lacus ex, sit amet blandit leo lobortis eget.
</Typography>
</ExpansionPanelDetails>
</ExpansionPanel>
</div>
);
}
Related documentation:
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Ordering_Flex_Items

Images not show in ReactJS carousal slider

I'm trying to use a Carousel slider on my website but all of the images are not showing. I'm using an example provided by a library but it's not working.
I've linked the Bootstrap CDN in my HTML file but it does not help.
import React, { Component } from 'react';
import {Carousel,} from 'react-bootstrap';
import Carousel from 'nuka-carousel';
class Slider extends Component {
render() {
return (
<Carousel autoplay={true}>
<img src="../asset/img1.jpg" />
<img src="http://placehold.it/1000x400/ffffff/c0392b/&text=slide2" />
<img src="http://placehold.it/1000x400/ffffff/c0392b/&text=slide3" />
<img src="http://placehold.it/1000x400/ffffff/c0392b/&text=slide4" />
<img src="http://placehold.it/1000x400/ffffff/c0392b/&text=slide5" />
<img src="http://placehold.it/1000x400/ffffff/c0392b/&text=slide6" />
</Carousel>
);
}
}
export default Slider;
You are using 2 different Carousels from 2 different library's I'm sure this will cause some issues.
Remove import Carousel from 'nuka-carousel';
I would stick to using react-bootstrap version
install package: npm install --save react-bootstrap
Add stylesheet to your HTML:
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
Make sure you are importing it properly like so:
import {Carousel} from 'react-bootstrap';
The example from the actual react-bootstrap
class ControlledCarousel extends React.Component {
constructor(props, context) {
super(props, context);
this.handleSelect = this.handleSelect.bind(this);
this.state = {
index: 0,
direction: null
};
}
handleSelect(selectedIndex, e) {
alert(`selected=${selectedIndex}, direction=${e.direction}`);
this.setState({
index: selectedIndex,
direction: e.direction
});
}
render() {
const { index, direction } = this.state;
return (
<Carousel
activeIndex={index}
direction={direction}
onSelect={this.handleSelect}
>
<Carousel.Item>
<img width={900} height={500} alt="900x500" src="/carousel.png" />
<Carousel.Caption>
<h3>First slide label</h3>
<p>Nulla vitae elit libero, a pharetra augue mollis interdum.</p>
</Carousel.Caption>
</Carousel.Item>
<Carousel.Item>
<img width={900} height={500} alt="900x500" src="/carousel.png" />
<Carousel.Caption>
<h3>Second slide label</h3>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
</Carousel.Caption>
</Carousel.Item>
<Carousel.Item>
<img width={900} height={500} alt="900x500" src="/carousel.png" />
<Carousel.Caption>
<h3>Third slide label</h3>
<p>
Praesent commodo cursus magna, vel scelerisque nisl consectetur.
</p>
</Carousel.Caption>
</Carousel.Item>
</Carousel>
);
}
}
render(<ControlledCarousel />);

Does deep nesting flexbox layout cause performance issue?

I have been working on a ReactJS project where I create most of the components using flexbox layout. Since with react, we can have deeply nested components, so my layout is having nested flexbox layout.
Now my question is, does this have any issue with performance? On a single page, there are many components and each component have 3 to 4 level nested flexbox layout. Will that cause a performance issue?
Have done a little test. Rendered 100 components, each with 10 nested layout. With and without flexbox. Here are the code snippets:
Component/index.js
#CSSModules(styles, { allowMultiple: true })
export default class TheComponent extends Component {
render() {
const { deepNest, flex } = this.props
return (
<div>{ this.renderComp(deepNest, flex) }</div>
)
}
renderComp(deepNest, flex) {
const flexProperties = [
{ justifyContent: "center", alignItems: "center" },
{ justifyContent: "flex-start", alignItems: "flex-end" },
{ flexDirection: "row" }
]
const content = [
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus interdum quis ligula vel elementum. Integer non rhoncus purus, eget dignissim ante.",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus interdum quis ligula vel elementum. Integer non rhoncus purus, eget dignissim ante. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus interdum quis ligula vel elementum. Integer non rhoncus purus, eget dignissim ante."
]
if (deepNest > 0 && flex) {
return (
<div styleName="containerFlex" style={flexProperties[deepNest % 3]}>
<div styleName="contentFlex" style={flexProperties[deepNest % 3]}>
{ content[deepNest % 3] }
</div>
<div styleName="nestedFlex" style={flexProperties[deepNest % 3]}>
{ this.renderComp(deepNest - 1, flex) }
</div>
</div>
)
}
if (deepNest > 0 && !flex) {
return (
<div styleName="container">
<div styleName="content">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus interdum quis ligula vel elementum. Integer non rhoncus purus, eget dignissim ante.
</div>
<div styleName="nested">
{ this.renderComp(deepNest - 1, flex) }
</div>
</div>
)
}
}
}
WithFlex/index.js
import TheComponent from "../Component"
#CSSModules(styles, { allowMultiple: true })
export default class WithFlex extends Component {
constructor(props) {
super(props)
this.state = { render: false }
}
render() {
const {render} = this.state
// number of components to render
const arr = _.range(100)
return (
<div>
<div
style={{ display: "block", padding: 30, lineHeight: "60px" }}
onClick={() => this.setState({render: !render})}>
Start Render
</div>
{ render && arr.map((i) => <TheComponent key={i} deepNest={10} flex={true}/> ) }
</div>
)
}
}
WithoutFlex/index.js
import TheComponent from "../Component"
#CSSModules(styles, { allowMultiple: true })
export default class WithoutFlex extends Component {
constructor(props) {
super(props)
this.state = { render: false }
}
render() {
const {render} = this.state
// number of components to renders
const arr = _.range(100)
return (
<div>
<div
style={{ display: "block", padding: 30, lineHeight: "60px" }}
onClick={() => this.setState({render: !render})}>
Start Render
</div>
{ render && arr.map((i) => <TheComponent key={i} deepNest={10} flex={false}/> ) }
</div>
)
}
}
Results from Chrome dev-tool timeline.
WithFlex
WithoutFlex
Summary
The difference is not that much. Also in flexbox, I put random properties to choose from. So I think it's alright with the performance. Hope it will help other devs.
Old flexbox (display: box) is 2.3x slower than new flexbox (display: flex).
Regular block layout (non-float), will usually be as fast or faster than new flexbox since it’s always single-pass. But new flexbox should be faster than using tables or writing custom JS-base layout code.
For more info
Article1
Article2

Resources