I'm using react-styled-components to style some custom components in my React/AntDesign application but the styles are not applied to my application.
When I tried reproducing the component in a clean codesandbox.io project the styles were applied successfully.
While some styled-components in my project do work this doesn't, what could be interfering with styled-components?
Here's the code:
import React from "react";
import "antd/dist/antd.css";
import styled from "styled-components";
import { FaMale, FaFemale, FaChild, FaUserFriends } from "react-icons/fa";
import { MdChildFriendly } from "react-icons/md";
import { Row, Col, Modal, Button } from 'antd';
class App extends React.Component {
state = { visible: false };
showModal = () => {
this.setState({
visible: true,
});
};
handleCancel = e => {
console.log(e);
this.setState({
visible: false,
});
};
ProductBtn = styled.div`
box-shadow: 0 0 15px rgba(0,0,0,0.1);
border: 1px solid #eee;
padding: 16px;
text-align: center;
border-radius: 5px;
cursor: pointer;
background-color: #fff
p {
margin-bottom: 0;
margin-top: 5px;
font-weight: bold;
}
`;
render() {
return (
<div>
<Button type="primary" onClick={this.showModal}>New Transaction</Button>
<Modal
title="New transaction"
visible={this.state.visible}
nOk={this.handleCancel}
onCancel={this.handleCancel}
>
<Row gutter={[16, 16]}>
<Col span={8}>
<this.ProductBtn onClick={this.handleProductClicked}>
<FaUserFriends style={{ fontSize: '24px' }} />
<p>Add couple</p>
<small>$70.00</small>
</this.ProductBtn>
</Col>
...
</Row>
</Modal>
</div>
)
}
}
export default App;
This is how it should look and how it looks in CodeSandbox:
This is how it looks in my application, without the widget/button-like styling on the ProductBtn styled component:
Related
Having the following components:
<CheckboxGroupLabel htmlFor={option.label}>
<FormCheckbox
onClick={() => onChange}
key={option.label}
defaultChecked={defaultChecked}
{...rest}
/>
{option.value}
</CheckboxGroupLabel>
Their styled components are:
import styled from 'styled-components';
import * as Checkbox from '#radix-ui/react-checkbox';
export const CheckboxGroupLabel = styled.label`
background-color: red;
display: flex;
width: 100%;
margin: 18px;
line-height: 20px;
cursor: pointer;
width: 100px;
`;
export const StyledCheckboxRoot = styled(Checkbox.Root)`
button {
all: unset;
}
`;
So the checkbox is inside label but only checkbox is clickable, I would like to make the whole label clickable.
Is there a way to do that?
Have you tried just moving onClick into CheckboxGroupLabel?
https://codesandbox.io/s/label-onclick-3ebkbi
import "./styles.css";
import * as Checkbox from "#radix-ui/react-checkbox";
import { CheckIcon } from "#radix-ui/react-icons";
export default function MyComponent() {
const onLabelClick = () => {
console.log("clicked label");
};
return (
<div>
<label onClick={onLabelClick} htmlFor="mycheckbox">
<Checkbox.Root className="checkbox" defaultChecked id="mycheckbox">
<Checkbox.Indicator className="indicator">
<CheckIcon />
</Checkbox.Indicator>
My checkbox label
</Checkbox.Root>
</label>
</div>
);
}
Whenever I try to style Antd Design component ( Layout, Sider and so on ) but it doesn't seems to be working. Therefore there won't be any changes on them. But it works fine on other HTML elements like div, h1, p tags.
Here's my code:
.sidbar{
flex: 1;
background-color: red;
border-right: 0.5px solid rgb(218, 217, 217);
min-height: 100vh;
background-color: white;
}
import styles from "../styles/Sidebar.module.scss";
import React from "react";
import { Layout, Menu } from "antd";
const { Header, Content, Footer, Sider } = Layout;
import {
HomeOutlined,
DashboardOutlined,
TeamOutlined,
} from "#ant-design/icons";
import Link from "next/link";
const Sidebar = () => {
return (
<div>
<Layout className={styles.sidebar}>
<Header>header</Header>
<Layout>
<Sider>left sidebar</Sider>
<Content>main content</Content>
<Sider>right sidebar</Sider>
</Layout>
<Footer>footer</Footer>
</Layout>
</div>
);
};
export default Sidebar;
I have a react app:
index.js
import React from "react";
import ReactDOM from "react-dom";
import { ThemeProvider } from "#material-ui/styles";
import { CssBaseline } from "#material-ui/core";
import Themes from "./themes";
import App from "./components/App";
import * as serviceWorker from "./serviceWorker";
import { LayoutProvider } from "./context/LayoutContext";
import { UserProvider } from "./context/UserContext";
import { GridPaginationProvider } from "context/GridPaginationContext";
import { ConfirmDialogServiceProvider } from "context/ConfirmDialogContext";
import "bootstrap/dist/css/bootstrap.css";
import "ag-grid-community/dist/styles/ag-grid.css";
import "ag-grid-community/dist/styles/ag-theme-material.css";
ReactDOM.render(
<LayoutProvider>
<UserProvider>
<GridPaginationProvider>
<ConfirmDialogServiceProvider>
<ThemeProvider theme={Themes.default}>
<CssBaseline />
<App />
</ThemeProvider>
</ConfirmDialogServiceProvider>
</GridPaginationProvider>
</UserProvider>
</LayoutProvider>,
document.getElementById("root")
);
serviceWorker.unregister();
here's the modal component:
import React from "react";
import { Button } from "#material-ui/core";
import { Modal, ModalHeader, ModalBody } from "reactstrap";
import "./confirm-dialog.scss";
const ConfirmDialog = ({
modalOptions,
open,
title,
icon,
variant,
description,
buttonTexts,
onSubmit,
onClose
}) => {
return (
<Modal isOpen={open} toggle={onClose} {...modalOptions} zIndex={1201}>
<ModalHeader toggle={onClose}>{title}</ModalHeader>
<ModalBody>
<div className="dialog">
<div className="dialog-icon">
<img src={icon} alt="icon" />
</div>
<div className="dialog-content">{description}</div>
<div className="dialog-actions">
<Button variant="contained" color="primary" onClick={onSubmit}>
{buttonTexts && buttonTexts.ok}
</Button>
<Button variant="contained" color="secondary" onClick={onClose}>
{buttonTexts && buttonTexts.cancel}
</Button>
</div>
</div>
</ModalBody>
</Modal>
);
};
export default ConfirmDialog;
confirm-dialog.scss
.modal {
z-index: 1201 !important;
&-content {
border-radius: 20px;
}
&-body {
padding: 0 30px 40px;
}
}
.dialog {
text-align: center;
&-content {
font-size: 16px;
color: #272727;
padding: 22px 0;
}
&-actions {
button {
margin: 0 10px;
font-size: 14px;
font-weight: normal;
min-width: 110px;
}
}
}
The problem is the css in confirm-dialog.scss is not overriding the bootstrap.css's .modal-* classes.
I don't understand what's the problem. The confirm dialog component has its own styles which should override the CSS from .css files imported in index.js file. The modal get triggered by a custom react-hook. The same modal dialog is working in my other project but in this project, the global bootstrap CSS is taking precedence over the confirm-dialog's own .scss.
Nevermind, figured it out. I just had to move all .css imports before App.js import in index.js file.
I am a little bit confused, when I am passing a method defined in the parent component, that is changing the view of the parent component down to a child component (e.g to a button in the child component), and when I click the button on the child component, does the method from parent component gets executed in the parent class (and therefore, on the parent view) or on the child class (and then on the child view)?
lets say I want to display an alert message on the parent class when the button in the child class gets clicked, the alert message will get displayed on the parent I guess.
But is it also possible to pass a method defined in the parent down to the child and then change some views in the child component?
EDIT:
I give an example for my problem:
I have a component to render conditionally in Parent Class:
I pass the method onShowAlert to show an alert on parent component
if (this.state.alleAnzeigen.length > 0) {
anzeigenListe = (
<AnzeigenComponent
anzeigenArray={this.state.alleAnzeigen}
onClickAlert={this.onShowAlert}
onButtonFinish={this.finishDocumentHandler}
/>
)
In my AnzeigenComponent, I pass the method down to Anzeige Component,
first, I had onClickalert={() => props.onClickAlert} without the (), however, in my Parent the method was not executed then.
const anzeigenArray = (props) => {
return props.anzeigenArray.map((anzeige,index) => (
<li className="mainList" key={anzeige.id} style={{padding: "10px"}} >
<Anzeige
anzeige={anzeige}
key={anzeige.id}
index={index}
onClickalert={() => props.onClickAlert()}
onButtonfinish={() => props.onButtonFinish(anzeige,index)}
/>
</li>
))
}
export default anzeigenArray;
my SubComponent "Anzeige" however, is a bigger Stateful Component Class:
when I click the button inside the singleAnzeige render function, I execute props.onClickalert()-> the method that I have passed down as props. However, the method doesn't do anything, unless I already execute that method with parentheses "()" in the component that I mentioned one above, I am just wondering, why is that so? Is there a limit of subcomponents where I can pass the method down only 2 levels or so, so that it still works?
import React, {Component} from 'react';
import DubletteComponent from '../components/DubletteComponent';
import { Button, Alert } from 'reactstrap';
import { Container, Row, Col } from 'reactstrap';
class Anzeige extends Component {
constructor(props) {
super(props);
}
singleAnzeige = (props) => {
// let newText = this.htmlspecialchars_decode("71065 Sindelfingen71032 Böblingen75365 Calw72202 Nagold71083 Herrenberg71229 Leonberg");
// console.log(newText);
return (
<Row>
<Col xs={12} md={2}><b>ID:</b> {props.anzeige.id}</Col>
<Col xs={12} md={3}><b>Titel:</b> {props.anzeige.title}</Col>
<Col xs={12} md={3}><b>Institution:</b> {props.anzeige.institution}</Col>
<Col xs={12} md={2}><b>Ort:</b> {props.anzeige.ort}</Col>
<Col xs={12} md={2} className="linkButton">
Link
<button className="finishButton" onClick = {
() => {
if (window.confirm('Are you sure you wish to finish this document?')) {
props.onButtonfinish(props.anzeige,props.index);
props.onClickalert();
}
}
}>fertig</button>
</Col>
<style jsx>
{`
p, a {
}
.linkButton {
flexDirection: 'row',
justifyContent: 'flex-end',
}
.anzeigeLink {
}
.finishButton:hover {
background-color: green;
}
.finishButton {
float: right;
border: 1px solid blue;
border-radius: 10px;
background-color: dark-green;
}
#media(max-width: 576px){
.finishButton {
float: none;
margin-right: 30px;
margin-left: 20px;
}
}
`}
</style>
</Row>
);
}
render() {
return (
<div className="anzeigeCard">
{this.singleAnzeige(this.props)}
<DubletteComponent className="dublette" anzeigeID={this.props.anzeige.id} onSendDoubletten = {this.props.onClickAlert}/>
<style jsx>
{`
.anzeigeCard {
border-radius: 10px;
padding: 10px;
margin: 5px 0px 5px 0px;
border: 1px solid light-green;
width: 100%;
box-shadow: 2px 2px 2px 2px;
}
`}
</style>
</div>
)
}
}
export default Anzeige
Is there a limit of subcomponents where I can pass the method down
only 2 levels or so, so that it still works?
There is no limit on how many levels you want to to pass your method as a prop,
if (this.state.alleAnzeigen.length > 0) {
anzeigenListe = (
<AnzeigenComponent
anzeigenArray={this.state.alleAnzeigen}
onClickAlert={this.onShowAlert}
onButtonFinish={this.finishDocumentHandler}
/>
)
}
const anzeigenArray = (props) => {
return props.anzeigenArray.map((anzeige,index) => (
<li className="mainList" key={anzeige.id} style={{padding: "10px"}} >
<Anzeige
anzeige={anzeige}
key={anzeige.id}
index={index}
onClickalert={props.onClickAlert}
onButtonfinish={props.onButtonFinish}
/>
</li>
))
}
export default anzeigenArray;
import React, {Component} from 'react';
import DubletteComponent from '../components/DubletteComponent';
import { Button, Alert } from 'reactstrap';
import { Container, Row, Col } from 'reactstrap';
class Anzeige extends Component {
constructor(props) {
super(props);
}
singleAnzeige = (props) => {
// let newText = this.htmlspecialchars_decode("71065 Sindelfingen71032 Böblingen75365 Calw72202 Nagold71083 Herrenberg71229 Leonberg");
// console.log(newText);
return (
<Row>
<Col xs={12} md={2}><b>ID:</b> {props.anzeige.id}</Col>
<Col xs={12} md={3}><b>Titel:</b> {props.anzeige.title}</Col>
<Col xs={12} md={3}><b>Institution:</b> {props.anzeige.institution}</Col>
<Col xs={12} md={2}><b>Ort:</b> {props.anzeige.ort}</Col>
<Col xs={12} md={2} className="linkButton">
Link
// I couldn't verify this code, but I guess your "if" implementation may cause some error, so in order to help you investigate easier, I remove the "if" here
<button className="finishButton" onClick = {
() => props.onButtonfinish(props.anzeige,props.index);
}>fertig</button>
</Col>
<style jsx>
{`
p, a {
}
.linkButton {
flexDirection: 'row',
justifyContent: 'flex-end',
}
.anzeigeLink {
}
.finishButton:hover {
background-color: green;
}
.finishButton {
float: right;
border: 1px solid blue;
border-radius: 10px;
background-color: dark-green;
}
#media(max-width: 576px){
.finishButton {
float: none;
margin-right: 30px;
margin-left: 20px;
}
}
`}
</style>
</Row>
);
}
render() {
return (
<div className="anzeigeCard">
{this.singleAnzeige(this.props)}
<DubletteComponent className="dublette" anzeigeID={this.props.anzeige.id} onSendDoubletten = {this.props.onClickAlert}/>
<style jsx>
{`
.anzeigeCard {
border-radius: 10px;
padding: 10px;
margin: 5px 0px 5px 0px;
border: 1px solid light-green;
width: 100%;
box-shadow: 2px 2px 2px 2px;
}
`}
</style>
</div>
)
}
}
export default Anzeige
When using the Card component from Material UI it seems like the CardContent has a padding-bottom of 24px that i cannot override with the following code. I can set paddingLeft, Right and Top using this method but for some reason paddingBottom won't work.
const styles = theme => ({
cardcontent: {
paddingLeft: 0,
paddingRight:0,
paddingTop:0,
paddingBottom: 0,
},
})
And then applying that style:
<CardContent className={classes.cardcontent}></CardContent>
this is what I see when previewing the elements in the browser:
.MuiCardContent-root-158:last-child {
padding-bottom: 24px;
}
.Component-cardcontent-153 {
padding-top: 0;
padding-left: 0;
padding-right: 0;
}
I can edit the pixels in the browser to 0. But I cannot figure out how to target MuiCardContent-root-158:last-child and override paddingBottom in my editor.
Here's the syntax for v3 and v4 (v5 example further down):
const styles = {
cardcontent: {
padding: 0,
"&:last-child": {
paddingBottom: 0
}
}
};
Here's a working example demonstrating this:
import React from "react";
import ReactDOM from "react-dom";
import CardContent from "#material-ui/core/CardContent";
import { withStyles } from "#material-ui/core/styles";
const styles = {
cardcontent: {
padding: 0,
"&:last-child": {
paddingBottom: 0
}
}
};
function App(props) {
return (
<div>
<CardContent
className={props.classes.cardcontent}
style={{ border: "1px solid black" }}
>
<div style={{ border: "1px solid red" }}>My Content</div>
</CardContent>
</div>
);
}
const StyledApp = withStyles(styles)(App);
const rootElement = document.getElementById("root");
ReactDOM.render(<StyledApp />, rootElement);
If you look at the CardContent source code, you can find how it defines the default styles:
export const styles = {
/* Styles applied to the root element. */
root: {
padding: 16,
'&:last-child': {
paddingBottom: 24,
},
},
};
This can be helpful in understanding how to override them.
For those using v5 of Material-UI, here's a v5 example (uses styled instead of withStyles):
import React from "react";
import ReactDOM from "react-dom";
import CardContent from "#mui/material/CardContent";
import { styled } from "#mui/material/styles";
const CardContentNoPadding = styled(CardContent)(`
padding: 0;
&:last-child {
padding-bottom: 0;
}
`);
function App(props) {
return (
<div>
<CardContentNoPadding style={{ border: "1px solid black" }}>
<div style={{ border: "1px solid red" }}>My Content</div>
</CardContentNoPadding>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
When setting the padding of Card Content to 0 via a theme override, the following works well:
overrides: {
MuiCardContent: {
root: {
padding: 0,
"&:last-child": {
paddingBottom: 0,
},
},
},
},
Here's the syntax for Mui.V5
<CardContent sx={{ p:0, '&:last-child': { pb: 0 }}}></CardContent>
add !important, it will override the root css