I'm trying to apply styling to tags that are generated from a for loop inside a function. The problem is that styling within a tag doesn't apply to these generated tags. Possibly because they're generated after the styling is applied? I'm not sure. Here's an example:
generateTags = (size) => {
let tags = []
for (var i = 0; i < size; i++) {
tags.push(<img className="image-tag" src={this.state.imagePath} alt="image" key={Math.random() * Math.floor(100000)}/>)
}
return tags
}
render() {
return (
<div className="main">
<div className="left-container">
{this.generateTags(10)}
</div>
<style jsx> {`
.main { <-- This is properly applied
position: relative;
width: 100%;
height: 100%;
}
.image-tag { <-- This doesn't work
position: absolute;
width: 50px;
}
`} </style>
</div>
)
}
The width: 50px is not applied to the image, and nothing I place makes any difference. But when I add styling within the tag like this:
<img className="image-tag" style={{width: "50px"}} src={this.state.imagePath} alt="image" key={Math.random() * Math.floor(100000)}/>
Then the style is applied correctly. Does this mean I can't have css within the style tag if the elements are return from a function?
It looks like you are using Styled JSX. One of the principles of Styled JSX is that the CSS is component specific. Since your <img> tags are being created outside of the render() function where your styles are defined, they are not being applied.
In this instance, I would recommend to instead have a GenerateTags React component, instead of a function. That way, you can generate your tags as needed, as well as apply component specific styling, like so:
GenerateTags = (props) => {
const {size} = props
let tags = []
for (var i = 0; i < size; i++) {
tags.push(i)
}
return(
<>
{tags.map((tag, index) => (
<img className="image-tag" src={this.state.imagePath} alt="image" key={Math.random() * Math.floor(100000)}/>
))}
<style jsx>{`
// This will now work as it is in the same scope as the component
.image-tag {
position: absolute;
width: 50px;
}
`}</style>
</>
)
return tags
}
render() {
return (
<div className="main">
<div className="left-container">
<GenerateTags size={10} />
</div>
<style jsx> {`
.main { <-- This is properly applied
position: relative;
width: 100%;
height: 100%;
}
`} </style>
</div>
)
}
Otherwise, if you wanted these styles to be applied outside of the scope of the component, you could use the global option:
<style jsx global>
...
</style>
I'm using Material-UI and building a timeline. My code is as follows:
<Timeline align="right" className={classes.monthlyContainer}>
<TimelineItem >
<TimelineSeparator className={classes.timelineSeparator}>
<TimelineDot className={classes.timelineDot} />
<TimelineConnector className={classes.timelineConnector} />
</TimelineSeparator>
{(data.map(url =>
<TimelineContent className={classes.memsImageContainer}>
<img
className={classes.memsImage}
src={url}
alt="MEMs"
/>
</TimelineContent>
))}
</TimelineItem>
</Timeline>
When I render the webpage, the Material-UI timeline keeps creating a .MuiTimelineItem-missingOppositeContent:before element which is shifting the layout of my timeline to the left.
When I inspect the element, this is what I see:
<li class="MuiTimelineItem-root MuiTimelineItem-alignRightMuiTimelineItem-missingOppositeContent">
<div class="MuiTimelineSeparator-root makeStyles-timelineSeparator-4">
<span class="MuiTimelineDot-root makeStyles-timelineDot-5 MuiTimelineDot-defaultGrey">
</span>
<span class="MuiTimelineConnector-root makeStyles-timelineConnector-6">
</span>
</div>
</li>
When I inspect the styles, this is what I have:
.MuiTimelineItem-missingOppositeContent:before {
flex: 1;
content: "";
padding: 6px 16px;
padding-left: 0px;
padding-right: 0px;
I have recreated it in codesandbox here
How can I remove this element?
The definition of the default styles for the missingOppositeContent element is as follows:
/* Styles applied to the root element if no there isn't TimelineOppositeContent provided. */
missingOppositeContent: {
'&:before': {
content: '""',
flex: 1,
padding: '6px 16px',
},
},
You can override the default styles using the same structure. Overriding this in the theme would look like the following:
const Theme = createMuiTheme({
overrides: {
MuiTimelineItem: {
missingOppositeContent: {
"&:before": {
display: "none"
}
}
}
}
});
You can also do this on a case-by-case basis (in case you have other situations in your code where you want the missing-opposite-content styling) using withStyles:
const TimelineItem = withStyles({
missingOppositeContent: {
"&:before": {
display: "none"
}
}
})(MuiTimelineItem);
You won't believe that you just need to add the <TimelineOppositeContent> component and set display property as 'none'. And it will be solved.
I have an app file which contains my own custom appbar and different page components:
const styles = theme => ({
appBar: {
width:'100%',
},
});
class App extends Component {
render() {
const {classes} = this.props;
return (
<React.Fragment>
<CssBaseline />
<AppBar position="sticky" className={classes.appBar} />
<Page1 show={someCondition} />
<Page2 show={someCondition} />
.
.
<Page99 show={someCondition} />
</React.Fragment>
);
}
}
The Appbar is sticky so it always shows on the top.
Each page component has a button which is always on the top of that page:
const styles = theme => ({
button: {
width:'100%',
},
});
class Page99 extends Component {
render() {
const {classes} = this.props;
return (
<React.Fragment>
<div>
<Button variant="contained" className= {classes.button}>
Action Button
</Button>
</div>
{/* Some other stuff */>
</React.Fragment>
);
}
}
I know want this button to always be right under the appbar. So when the user scrolls down this button should remain sticky just like the appbar does. I tried to set the positioning to sticky hoping it would stack underneath it but it wouldn't. The appbar is dynamic so I don't know the exact height it will be since on different resolutions it will look different so I couldn't use something like fixed positioning.
You can set position of page container as relative and set button as absolute.
the you can align it to top right of the page or wherever you want.
Check this fiddle is this is what you need
.componentparent {
position: relative;
height:100px;
max-height: 50px;
overflow: auto;
}
.button {
position: fixed;
top: 30px;
}
.otherelements{
top: 70px;
position: relative;
}
<div id="parent-container">
<div> your app bar </div>
<div class='componentparent'>
<button class='button'>my button</button>
<div class='otherelements'>your component</div>
</div>
</div>
Place your button inside your appbar and set your button to position to absolute and add top: 100% to move it exactly at the bottom of appbar.
I have a simple router configuration:
<Router history={browserHistory}>
<Route lang="en" path="en" component={App}>
<Route path="*" component={PageFactory} />
</Route>
<Redirect from="*" to="/en/*" />
</Router>
and main App component has the following:
<div className="app">
<Home />
<Sidebar {...sidebarProps}>
{this.props.children}
</Sidebar>
</div>
So, the Home component always opens when you open the react application. When I click a link in Home component (e.g /en/pages/about-page), the contents of the page gets loaded to Sidebar component and Sidebar gets a prop isOpen (That's what ...sidebarProps is for). Everything works fine. When I click a link Sidebar opens, and contents show with overlay etc. However, transitions do not animate. Here is my CSS:
.sidebar {
position: fixed;
left: 0px;
top: 0px;
width: 100%;
height: 100%;
z-index: 200;
visibility: hidden;
background: rgba(0, 0, 0, 0.8);
overflow: scroll;
#include transition(visibility 0s linear 0.3s);
&.is-open {
visibility: visible;
#include transition-delay(0s);
.sidebar-content {
#include transform(translateX(0));
}
}
}
The isOpen prop in Sidebar adds class is-open to root element of Sidebar component. Here is Sidebar component for reference:
const Sidebar = props =>
<aside className={`sidebar ${props.isOpen ? ' is-open' : ''}`}>
<SidebarContent>{props.children}</SidebarContent>
</aside>
;
For testing to see whether it is a React problem, I added a button like the following to my App component:
constructor(props) {
super(props);
this.enableSidebar = this.enableSidebar.bind(this);
this.state = { isOpen: false };
}
enableSidebar() {
this.setState({ isOpen: true });
}
render() {
const sidebarProps = { isOpen: this.state.isOpen };
return (
<div className="app">
<button onClick={this.enableSidebar}>Enable Sidebar</button>
<Home />
<Sidebar {...sidebarProps}>{this.props.children></Sidebar>
</div>
);
}
And when I click the button, sidebar opens smoothly. It is React Router that completely reloads the page on every request, making every page be a static page instead of creating a dynamic application.
How can I change this behavior? How can I make React Router to not reload all components on route change? I am thinking that maybe the structure that I have is problematic. If you also think it is, can you suggest me a solution?
I have found the problem. I had to use React Router Link component instead of HTML anchor element. So instead of using:
About
I have to use:
<Link to="/en/pages/about-page">About</Link>
I've made a sticky footer higher-level component that wraps other components inside itself:
Footer.js
//this is a higher-order component that wraps other components placing them in footer
var style = {
backgroundColor: "#F8F8F8",
borderTop: "1px solid #E7E7E7",
textAlign: "center",
padding: "20px",
position: "fixed",
left: "0",
bottom: "0",
height: "60px",
width: "100%",
};
const Footer = React.createClass({
render: function() {
return (
<div style={style}>
{this.props.children}
</div>
);
}
});
export default Footer;
Usage:
<Footer><Button>test</Button></Footer>
But it is hiding the contents of the page:
This looks like a common problem, so I searched a bit and found this issue, where is FlexBox is recommended for the sticky footer. But at this demo the footer is at the very bottom of the page, while I need the footer to be always displayed on the page and the content being scrolled inside the above area (like in SO chat). In addition to that, there is an advice to change all the other components with custom stylesheet rules. Is it possible to achieve what I need using styling only the footer component so the code will remain modular?
Here's an idea (sandbox example link).
Include a phantom div in your footer component that represents the footer's position that other dom elements will respect (i.e. affecting page flow by not being position: 'fixed';).
var style = {
backgroundColor: "#F8F8F8",
borderTop: "1px solid #E7E7E7",
textAlign: "center",
padding: "20px",
position: "fixed",
left: "0",
bottom: "0",
height: "60px",
width: "100%",
}
var phantom = {
display: 'block',
padding: '20px',
height: '60px',
width: '100%',
}
function Footer({ children }) {
return (
<div>
<div style={phantom} />
<div style={style}>
{ children }
</div>
</div>
)
}
export default Footer
Much easier idea (following the trend), i imported both bootstrap and reactstrap, used the bootstrap fixed bottom class and workaround with that like this.
class AppFooter extends Component{
render() {
return(
<div className="fixed-bottom">
<Navbar color="dark" dark>
<Container>
<NavbarBrand>Footer</NavbarBrand>
</Container>
</Navbar>
</div>
)
}
There is a much simpler way. I am creating a portfolio site with React, and some of my pages are not very long, so in some devices, like kindle fire hd for example, the footer would not stick to the bottom. And of course to set this up in the traditional fashion with would not work, because the would be wrapped in there. And we don't want that. So this is what I did:
In App.js:
import React, { Component } from 'react';
import {Header} from './components/Header';
import {Main} from './components/Main';
import {Footer} from './components/Footer';
class App extends Component {
render() {
return (
<div className="App Site">
<div className="Site-content">
<div className="App-header">
<Header />
</div>
<div className="main">
<Main />
</div>
</div>
<Footer />
</div>
);
}
}
export default App;
And then in _sticky-footer.css (I use POSTCSS):
:root {
--space: 1.5em 0;
--space: 2em 0;
}
.Site {
display: flex;
flex-direction: column;
min-height: 100vh;
}
.Site-content {
flex: 1 0 auto;
padding: var(--space) var(--space) 0;
width: 100%;
}
.Site-content:after {
content: '\00a0';
display: block;
margin-top: var(--space);
height: 0;
visibility: hidden;
}
The original solution for this was created by Philip Walton: https://philipwalton.github.io/solved-by-flexbox/demos/sticky-footer/
You can fix this by adding margin-bottom: 60px; to the body of your website. With the 60px being the height of your footer.
.footer{
width: 100%;
position: fixed;
bottom: 0;
}
This should do the trick! Cheers! (:
.App will be the main component you load to your Root.
Assume that the footer is the last child of .App in the document flow
.App {
height: 100vh;
display: flex;
flex-direction: column;
}
footer {
margin-top: auto;
}
I found that if you wrap your 'footer' component in a standard html
<footer>
tag, it pretty much sorts out all of the positioning for you
I wanted to share this solution that worked. I cribbed this from https://react.semantic-ui.com/modules/sticky. Scroll to the bottom of this page and inspect the text 'This is the bottom' to see where I stole it. Its a site built on react so it should work for your situation.
Here it is:
{
padding-top: 50vh;
}
Conceptually, this solution is creating negative space like jacoballenwood's phantom div to push the footer down to the bottom and stick it there. Just add it to your css style class for the footer and adjust the value to taste.
Very late answer, but someone can find this useful. You can, instead of phantom style, set Toolbar. I have build some standard layout for the components, where {children} is component from the parent component - App.js. This is example:
import React from "react";
import { Route } from "react-router-dom";
import { makeStyles } from "#material-ui/core/styles";
import AppBar from "#material-ui/core/AppBar";
import CssBaseline from "#material-ui/core/CssBaseline";
import Toolbar from "#material-ui/core/Toolbar";
import Header from "../components/header";
import Footer from "../components/footer";
import SideBar from "../components/sidebar";
const useStyles = makeStyles((theme) => ({
root: {
display: "flex",
},
appBar: {
zIndex: theme.zIndex.drawer + 1,
},
content: {
flexGrow: 5,
padding: theme.spacing(3),
},
}));
const StandardLayout = ({ children }) => {
const classes = useStyles();
return (
<div className={classes.root}>
<CssBaseline />
<AppBar position="fixed" className={classes.appBar}>
<Route path="/" component={Header} />
</AppBar>
<SideBar />
<main className={classes.content}>
<Toolbar />
<br />
{children}
<Toolbar/>
</main>
<AppBar className={classes.appBar}>
<Route path="/" component={Footer} />
</AppBar>
</div>
);
};
export default StandardLayout;
Its rule for me
<footer style={{position:"fixed",bottom:"0"}}>
Try this html code:
/public/index.html
<html lang="en" class="h-100">
<body class="h-100">
<div id="root" class="d-flex flex-column h-100"></div>
...
/src/App.js
<main role='main' className='flex-shrink-0'>
You can follow this template:
react-bootstrap-sticky-footer/public/index.html
react-bootstrap-sticky-footer/src/App.js