I am quite new to Material UI # next, and I like the fact that it supports Styled Components.
However, I am struggling in aligning the Button component to the center through Styled Components. I only manage to align it by using the styles technique such as this:
const styles = {
container: {
textAlign: "center"
}
};
class Landing extends Component {
render() {
return (
...
<div style={styles.container}>
<Button variant="raised" color="primary">
I am a button
</Button>
</div>
);
}
}
This is something that I like to avoid, and instead use the Styled Components such as:
const Container = styled.div`
text-align: "center";
`;
However, for some reason it is not working although they look exactly identical. Can someone explain whether text-align and textAlign are pointing to the same CSS property?
It works using styled component here is the code
import React from 'react';
import Button from "react-bootstrap/es/Button";
import styled from 'styled-components';
const Container = styled.div`
text-align: center;
`;
class Landing extends React.Component {
render() {
return (
<Container>
<div>
<Button color="primary">
I am a button
</Button>
</div>
</Container>
)};
};
You have to wrap the styled component which you have taken. Here I've taken container and then inside the container, I've added the needed CSS.
For more information and usage about the styled component, you can visit this URL - https://www.styled-components.com/docs/basics
Thanks
Related
I am trying to have custom width for antd tooltip component: Link to docs
How can this be done ?
import React from "react";
import ReactDOM from "react-dom";
import "antd/dist/antd.css";
import { Tooltip } from "antd";
import styled from "styled-components";
const Styled = styled.div`
.ant-tooltip-inner {
color: yellow;
background-color: green;
width: 800px;
}
`;
ReactDOM.render(
<Styled>
<Tooltip title="prompt text">
<span>Tooltip will show on mouse enter.</span>
</Tooltip>
</Styled>,
document.getElementById("container")
);
The antd Tooltips docs gives you a hint for your issue. The Tooltip is added as div in the body by default, in fact your custom style won't work without any adaptions. Depending on your requirements you can use
GlobalStyle from Styled Components
Overwrite getPopupContainer from Antd Tooltip
GlobalStyle
As one workaround you can use the globalStyle
const GlobalStyle = createGlobalStyle`
body {
.ant-tooltip-inner {
color: yellow;
background-color: green;
width: 800px;
}
}
`;
ReactDOM.render(
<Tooltip title="prompt text">
<GlobalStyle />
<span>Tooltip will show on mouse enter.</span>
</Tooltip>,
document.getElementById("container")
);
Here is a CodeSandbox for this workaround.
getPopupContainer
From the Tooltip docs for getPopupContainer
The DOM container of the tip, the default behavior is to create a div
element in body
Here you can just pass the triggerNode to be the parent object and your styles are set as expected.
const Styled = styled.div`
.ant-tooltip-inner {
color: yellow;
background-color: green;
width: 800px;
}
`;
ReactDOM.render(
<Styled>
<Tooltip title="prompt text" getPopupContainer={(triggerNode) => triggerNode}>
<span>Tooltip will show on mouse enter.</span>
</Tooltip>
</Styled>,
document.getElementById("container")
);
Working CodeSandBox for using getPopupContainer.
The default behavior for DOM container of the tip is to create a div element in body. You can change it to create inside Tooltip element with getPopupContainer:
<Tooltip
getPopupContainer={(trigger) => {
console.log(trigger);
return trigger;
}}
title="prompt text"
>
With the code above you style .ant-tooltip-inner will work.
For more info, check this link -> Tooltip Antd API
I have created a Container component with component styles in next.js.
When I declare use of this container component throughout my site, I would like to add a className to it and subjectively style it depending on the context of its use.
Here is an example of my Container component:
const Container = (props) => (
<>
<div className="container">
{props.children}
</div>
<style jsx>{`
.container{
width: 100%;
max-width: 1200px;
margin: 0 auto;
}
`}</style>
</>
)
export default Container;
So, I want to give it a maximum width of 1200px, and centre it with auto margins. No problem, I have done that.
Now, I am planning to use this component in the header of my site. But in the case of the header, I would like the Container component to be a flexbox:
import Container from './Container'
const Header = (props) => (
<>
<header>
<Container className="header-col">
<div>
<h1>{props.title}</h1>
</div>
<nav>
<ul>
{/* Navigation items */}
</ul>
</nav>
</Container>
</header>
<style jsx>{`
.header-col{
display: flex;
justify-content: space-between;
}
`}</style>
</>
)
export default Header;
When I view the site, I noticed the flexbox style I specified for the Container component in the header is not present.
I was expecting the className to take effect, and allow me to add additional styles.
I believe this has something to do with it thinking that className is not a class name, rather props. But, I want to keep my code dry by creating style inheritance on components.
How could I do this?
Thanks for the help!
This is a job for styled components:
import React from "react";
import styled from "styled-components";
export default function App() {
return (
<>
<Container custom={"header"}>
<h1>Very fancy h1 with flex display</h1>
</Container>
<Container custom={"regular"}>
<h1>Non-fancy h1 with no flex display</h1>
</Container>
</>
);
}
const Container = styled.div`
display: ${(props) => (props.custom === "header" ? "flex" : "block")};
/* you can call your prop ^^^^^^ whatever you want,
just change it on the container element too*/
& h1 {
/* you can apply css to children like so */
font-family: ${(props) =>
props.custom === "header"
? '"Courier New", Courier, monospace'
: '"Arial Black", Gadget, sans-serif'};
}
`;
In the above, I've created a custom styled component that receives the custom prop and then conditionally changes the values you are looking to adjust. To make the changes more visible to the eye, I've also styled the font so you can see the immediate difference between the two <Container> elements.
For a solution that is more scalable (e.g., for different themes), use ThemeProvider:
import React from "react";
import styled, { ThemeProvider } from "styled-components";
export default function App() {
return (
<>
<ThemeProvider theme={ContainerHeader}>
<Container>
<h1>Very fancy h1 with flex display</h1>
</Container>
</ThemeProvider>
<Container theme={"regular"}>
<h1>Non-fancy h1 with no flex display</h1>
</Container>
</>
);
}
const Container = styled.div`
display: ${(props) => props.theme.display};
& h1 {
font-family: ${(props) => props.theme.h1Font};
}
`;
Container.defaultProps = {
theme: {
display: "block",
h1Font: '"Arial Black", Gadget, sans-serif'
}
};
const ContainerHeader = {
display: "flex",
h1Font: '"Courier New", Courier, monospace'
};
CodeSandbox: https://codesandbox.io/s/stack-conditional-styled-components-vmnpn?file=/src/App.js:0-773
I believe I have found the answer to my own question (I will still leave this question open for a couple more days just in case it can be improved).
In order to pass styles, you can add the "global" flag to the styled JSX and append additional classnames in the component with props.className.
Parent Container component using props.className:
const Container = (props) => (
<>
<div className={`container ${props.className}`}>
{props.children}
</div>
<style jsx>{`
.container{
width: 100%;
max-width: 1200px;
margin: 0 auto;
}
`}</style>
</>
)
export default Container;
Then, when you want to use that component, you can add additional styles with the global flag in the <style jsx>:
Container being used and styled even more in the header:
import Container from './Container';
const Header = (props) => (
<>
<header>
<Container className="header-col">
<div>
<h1>{props.title}</h1>
</div>
<nav>
<ul>
<li>Hello</li>
<li>There</li>
</ul>
</nav>
</Container>
</header>
<style jsx global>{`
.header-col{
display: flex;
justify-content: space-between;
}
`}</style>
</>
)
export default Header;
This is not 100% perfect though (but in my opinion it is still pretty good):
The global flag makes your styles global. So other components can use
these styles (I believe)
You need to make sure your components take in props.className to append additional classnames for this global style
I have the following CSS:
[contentEditable=true]:empty:not(:focus):before{
content:attr(data-text)
}
which allows to show a placeholder inside a content-editable div when it has no content. I am using Material-UI Styles, so I need something like:
const styles = theme => ({
div[contentEditable=true]:empty:not(:focus):before: {
content:attr(data-text)
}
});
How could I achieve this? Any idea?
Thank you.
Below are a couple syntax options depending on whether you want to specify the class directly on the div (editableDiv) or on an ancestor element (container). The only difference between the two is the space after & when targeting descendants.
import React from "react";
import ReactDOM from "react-dom";
import { makeStyles } from "#material-ui/core/styles";
const useStyles = makeStyles({
container: {
"& [contentEditable=true]:empty:not(:focus):before": {
content: "attr(data-text)"
}
},
editableDiv: {
"&[contentEditable=true]:empty:not(:focus):before": {
content: "attr(data-text)"
}
}
});
function App() {
const classes = useStyles();
return (
<div>
<div className={classes.container}>
<div contentEditable data-text="Click here to edit div 1" />
<div contentEditable data-text="Click here to edit div 2" />
</div>
<div
className={classes.editableDiv}
contentEditable
data-text="Click here to edit div 3"
/>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Related documentation: https://cssinjs.org/jss-plugin-nested?v=v10.0.0#use--to-reference-selector-of-the-parent-rule
I am a bit puzzled when following the documentation here. Everything seems to work other than the headerStyle attribute. It doesn't seem to be applying to styles that I apply to it. I'm not sure where I am going wrong.
Checking CodeSandbox from one of the examples provided headerStyle works. Where else can I check to understand what is causing this issue?
Localhost:
Codesandbox:
Not sure where your problem lies, as I'm not getting the same warning (when using headerStyle), but here's a working example -- make sure to import the ant design css, otherwise, the ant components won't work as intended. Also, I find it easier and cleaner to override ant's css via overriding their respective class names in a separate css file, rather than overriding styles -- especially when overriding more than css property.
index.js
import React, { Component } from "react";
import { render } from "react-dom";
import { Drawer, Button } from "antd";
import "antd/dist/antd.css";
import "./index.css";
class App extends Component {
state = { visible: false };
showDrawer = () => {
this.setState(prevState => ({
visible: !prevState.visible
}));
};
render() {
return (
<div>
<Button type="primary" onClick={this.showDrawer}>
Open
</Button>
<Drawer
title="Basic Drawer"
placement="right"
closable={false}
onClose={this.showDrawer}
visible={this.state.visible}
>
<p>Some contents...</p>
<p>Some contents...</p>
<p>Some contents...</p>
</Drawer>
</div>
);
}
}
render(<App />, document.getElementById("container"));
index.css
.ant-drawer-header {
background-color: #5340ff;
border-radius: 0;
}
.ant-drawer-title {
color: #fff;
}
.ant-drawer-body {
background-color: #5340ff;
color: #fff;
height: calc(100vh - 55px);
}
So I'm trying to create a navigational menu header and it also includes a logo in it, fairly simple but some of the buttons the left side are inline-block with the logo itself and they appear at the bottom of the logo, to the right of it based on ordering, but at the bottom and im not sure how with css to get them to go to the top of the container or if the roof of their container is just lower that I'm thinking?
import React from 'react';
import {Link} from 'react-router-dom';
import { AuthService } from './backend/client/auth';
import { Paper, Button } from '#material-ui/core';
import { withStyles } from '#material-ui/core/styles';
const styles = theme => ({
container: {
'height': 128,
},
leftnav: {
'display': 'inline-block',
},
rightnav: {
'float': 'right',
},
button: {
'display': 'inline-block',
}
});
class Header extends React.Component {
render() {
const { classes } = this.props;
return (
<Paper className={classes.container}>
<div className={classes.leftnav}>
<Link to="/" className={classes.button}>
<img src="https://imageserver.eveonline.com/Corporation/98523546_128.png" alt="Hole Puncher's Logo"></img>
</Link>
<Button component={Link} to="/">
Home
</Button>
<Button component={Link} to="/store">
Browse
</Button>
<Button component={Link} to="/contact-us">
Contact Us
</Button>
</div>
<div className={classes.rightnav}>
{AuthService.isAuthed()
? <Button component={Link} to="/account/orders">Account</Button>
: ''}
{AuthService.isAuthed()
? <Button component={Link} to="/login">Login</Button>
: <Button onClick={AuthService.logout} component={Link} to="/login"></Button>}
</div>
</Paper>
)
}
}
export default withStyles(styles)(Header);
https://i.imgur.com/OnTjO4l.png
Multiple ways to solve it using CSS. Simplest way is to use vertical-align: top in your button class. I would however recommend you look into display: flex. It's much easier for vertical alignment.
Working JSFiddle here: http://jsfiddle.net/Lhefbudx/
Hope this helps.