I am trying to add class names to a React Component to make it easier for me to customize that component using Styled Components. Here is a simplified outline of the component:
const SignupForm = props => (
<form>
<Input className="input" />
<Button className="button" />
</form>
)
And here is how I would like to use it:
import { SignupForm } from '../path/to/signup-form'
<Form />
...
const Form = styled(SignupForm)`
.input {
/* Custom Styles */
}
.button {
/* Custom Styles */
}
`
However, this does not work. Only if I create a wrapper Component will it work - like this:
import { SignupForm } from '../path/to/signup-form'
<FormWrapper>
<SignupForm/>
<FormWrapper>
...
const FormWrapper = styled.div`
.input {
/* Custom Styles */
}
.button {
/* Custom Styles */
}
`
I'm wondering whether or not there is a way to access the .input and .button classes without having to create a wrapper class, i.e. via the actual imported class itself? If so, how?
You need to provide className for the wrapper/container as styled-component injecting the styles through it:
const SignupForm = ({ className }) => (
<form className={className}>
<input className="input" />
<button className="button">Button</button>
</form>
);
const Form = styled(SignupForm)`
.input {
background-color: palegreen;
}
.button {
background-color: palevioletred;
}
`;
Just add extra atrribute className by using attrs to existing styled component.
const FormWrapper = styled.div.attrs({
className: 'SignupForm',
})`
.input {
/* Custom Styles */
}
.button {
/* Custom Styles */
}
`
Related
I am creating a div using styled component. I want to change the visibility of the div on button clicked,
const Category = () => {
const [showCategory, setShowCategory] = useState(false)
useEffect(() => {
setShowCategory(false)
}, [])
return (
<button onClick={() => { setShowCategory(true)}}>
New Category
</button>
<AdminInputStyle>
<form>
<form-group>
<label>Add Category</label>
<input type='text' />
</form-group>
<button>Submit</button>
</form>
</AdminInputStyle>
)
}
Here's the styled component
const AdminInputStyle = styled.div`
display: ${(d) => (d.showCategory ? 'show' : 'hidden')};
`
You can try something like this too, show when you need to show the add category when you press add category
return (
<>
<button
onClick={() => {
setShowCategory(true);
}}
>
New Category
</button>
{showCategory && (
<AdminInputStyle>
<form>
<form-group>
<label>Add Category</label>
<input type="text" />
</form-group>
<button>Submit</button>
</form>
</AdminInputStyle>
)}
</>
);
I have an example, but in the case we will use a Button. Clicking it will alter the visibility.
You must pass a property to the styled component if you want it to be visible based on that prop. In your example, you don't pass a prop to the styled component in this scenario, which is why the component cannot detect if it should be visible or not.
You will need to / can use the css function from the styled-components library. This can help you return styles based on the properties your styled-component will have. In this example, our property that we pass to the button will be called visible.
import React from 'react';
import PropTypes from 'prop-types';
import styled, { css } from 'styled-components/macro';
const StyledButton = styled.button`
border-radius: 3px;
color: white;
background-color: green;
cursor: pointer;
width: 100px;
height: 50px;
${({ visible }) => {
return css`
visibility: ${visible ? 'visible' : 'hidden'};
`;
}}
`;
export default function Button({ children, visible, onClick }) {
return (
<StyledButton visible={visible} onClick={onClick}>
{children}
</StyledButton>
);
}
Button.propTypes = {
children: PropTypes.node,
visible: PropTypes.bool,
onClick: PropTypes.func,
};
You can see that passing the visible prop will enable the button to alter its' styles based on whether that property is true or false. We utilize a function within the component that returns the css function and this will control the visibility css property.
Here is how we utilize the button and pass props to it from another component; in this example just the App.js file:
import React, { useState } from 'react';
import './App.css';
import Button from './components/Button';
function App() {
const [visible, setVisible] = useState(true);
function handleClick() {
setVisible(!visible);
}
return (
<div className="App">
<Button visible={visible} onClick={handleClick}>
Click
</Button>
</div>
);
}
export default App;
FYI: For the css; you don't want display: hidden;. hidden is an invalid value for the display prop. You'd want display: none; if you don't want the element to be in the DOM. visibility: hidden; will add the element to the DOM, but it won't be visible. You can use whichever works best for your case 👍🏿
I have made a separate useStyle file and want to use this custom css in useStyle of material ui. How to achieve that?
input[type="checkbox"],
input[type="radio"] {
display: none;
}
Let's say your useStyles file looks something like this:
import makeStyles from "#material-ui/core/styles/makeStyles";
const useStyles = makeStyles({
hideCheckboxAndRadio: {
"& input[type='checkbox'], & input[type='radio']": {
display: "none"
}
}
});
export default useStyles;
Back on your components, just import this file and attach it to a parent where you want all of its children input of type radio & checkbox to be hidden
import useStyles from "./useStyles";
function App() {
const classes = useStyles();
return (
<div className={classes.hideCheckboxAndRadio}>
<input type="text" />
<input type="checkbox" />
<input type="radio" />
</div>
);
}
I have a problem on which I cannot find a simple solution. So this is my Header:
const Header = ({ title }) => {
return (
<div className={styles.Header}>
<h1>{title}</h1>
<button>
{EXIT}
</button>
</div>
);
};
How can I apply custom styles with styled-components for h1 and button elements? I tried
const CustomHeader = styled(Header)`
${h1} ${button}
`;
const h1 = styled(h1)`
max-width: 500px
`
const button = styled(button)`
padding-left: 100px
`
but this is not working, I get an error in terminal.
I also tried this:
return (
<CustomHeader>
<div className={styles.Header}>
<h1>{title}</h1>
<button>
{EXIT}
</button>
</div>
</CustomHeader>
);
};
const CustomHeader = styled(Header)`
h1 {
max-width: 500px;
}
button {
padding-left: 100px;
}
`;
Any help will be appreciated.
First you need to define styled component in your React function and create a wrapper like following:
// added demo css here for h1 tag, you can add your own
const CustomHeader = styled.div`
h1 {
font-family: Poppins;
font-size: 14px;
font-weight: 600;
font-stretch: normal;
font-style: normal;
line-height: 1.5;
letter-spacing: 0.02px;
text-align: left;
color: #0f173a;
}
`;
Then wrap your return inside the CustomHeader wrapper.
const Header = ({ title }) => {
return (
<CustomHeader>
<h1>{title}</h1>
<button>
{EXIT}
</button>
</CustomHeader>
);
};
You can add any tag inside CustomHeader that you want to customize.
You're almost there.
Its not working because you are setting className directly on div element of your Header component.
According to the styled-component documentation:
The styled method works perfectly on all of your own or any third-party components, as long as they attach the passed className prop to a DOM element.
https://styled-components.com/docs/basics#styling-any-component
So, in your case you need to:
const Header = ({ title, className }) => {
return (
<div className={className}>
<h1>{title}</h1>
<button>EXIT</button>
</div>
);
};
const CustomHeader = window.styled(Header)`
h1 {
max-width: 500px;
}
button {
padding-left: 100px;
}
`;
const App = () => {
return (
<React.Fragment>
<Header className='' title={"title"} />
<CustomHeader title={"title"} />
</React.Fragment>
);
};
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<script src="//unpkg.com/styled-components#4.0.1/dist/styled-components.min.js"></script>
<div id="root"></div>
So, i set Header like this:
const Header = ({ title, className }) => {
return (
<div className={className}>
And where i did <Header className='' title={"title"} /> you can do like this:
<Header className={styles.Header} title={"title"} />
// Code
const Header = ({ title }) => {
return (
<Header>
<h1>{title}</h1>
<button>
{EXIT}
</button>
</Header>
);
};
// Styles
const Header = styled.div`
h1{
styles...
}
button{
styles...
}
`;
is it possible to make selector for child component prop in styled components?
<Accordion>
<Checkbox checked='false' />
<Text>Text to be hidden when checked is false</Text>
</Accordion>
I would like to access the prop something like this:
const Accordion = styled.div`
& > ${Checkbox}[checked='false'] ~ ${Text} {
display: none;
}
`;
Is it possible and if so, how should I do it?
You are trying to use Attribute selectors, so you need to define valid attributes on Checkbox component like data-*.
If you trying to use component's property, you have to lift the state up (see Text with "State from Parent").
const Checkbox = styled.div``;
const Text = styled.div``;
const Accordion = styled.div`
& > ${Checkbox}[data-checked="true"] ~ ${Text} {
color: palevioletred;
font-weight: 600;
&:last-child {
color: ${prop => (prop.checked ? `blue` : `orange`)};
}
}
& > ${Text}[title="example"]{
border: 1px solid black;
}
`;
const App = () => {
return (
<Accordion checked>
<Checkbox data-checked="true" checked="true">
I'm Check box
</Checkbox>
<Text title="example">With attr gives border</Text>
<Text>Without attr</Text>
<Text>State from Parent</Text>
</Accordion>
);
};
I am writing a React application with styled components, creating a library of reusable components for my application, but I encounter the problem of inheritance between sister components when trying to give a property to a label that is next to my input when the input is required, but it does not work. I have tried with:
// Form.js
import { StyledLabel, StyledInput } from './styles.js'
<StyledLabel>Mi Label 1</StyledLabel>
<StyledInput required/>
// ./styles.js
import styled from 'styled-components'
export const StyledInput = styled.input`
border: 1px #dddd solid;
`
export const StyledLabel = styled.label`
font-size: 10px;
${StyledInput}['required'] + & {
&::after {
content: '*'
}
}
`
The result only returns the form without the *
Does anyone know how I can detect from Styled Components when an input has the required HTML attribute, and show the *
Pseudo-selectors in styled-components work just like they do in CSS. (or rather, Sass).
So you can do what you want this way:
const Wrapper = styled.div`
label {
&:after {
content: "${p => p.required && "*"}";
color: red;
}
}`;
const Form = () => {
return (
<Wrapper required>
<label>Mi Label 1</label>
<input />
</Wrapper>
);
};
But if you want don't want to pass props of the input element to its parent you can
do it this way:
const Wrapper = styled.div`
display: flex;
flex-direction: row-reverse;
align-items: center;
`;
const Example = styled.input`
+ label {
&:after {
content: "${p => p.required && "*"}";
color: red;
}
}
`;
const Form = () => {
return (
<Wrapper required>
<Example />
<label>My Label 1</label>
</Wrapper>
);
};
more info in resources:
Before and After pseudo classes used with styled-components
https://github.com/styled-components/styled-components/issues/388
https://github.com/styled-components/styled-components/issues/74