Extend a Styled Component from a different file - reactjs

What I'm trying to achieve is to be able to add extra styling to my Button.tsx(essentially extending the styles) when using this component in different files. As you can see in my Button.tsx I have defined some default styles I would like the button to have, but as I use more buttons across my app, I might want to change the background or color, etc.
One thing I could do is this:
Example of not what I want to do:
import React from 'react'
import styled from 'styled-components'
interface IButton = {
children: string
}
export default function Button({ children }: IButton) {
const Button = styled.button`
padding: 1em;
background: #ccc;
border-radius: 5px;
`
const RedButton = styled(Button)`
// Inherits all of the styles from Button.
background: red;
`
return (
<Button>{children}</Button
)
}
This example will inherit my Button styles and then allows me to extend. The problem with this solution is, if I decide to add more buttons, I will always have to come back to this file and then add the different variants, which could start to make this file get pretty chunky and messy.
Ideally I would like to extend my <Button> from the App.tsx file, or which ever file I'm using my <Button> in.
How could I adjust the code below to achieve this?
Button.tsx
import React from 'react'
import styled from 'styled-components'
interface IButton = {
children: string
}
export default function Button({ children }: IButton) {
const Button = styled.button`
padding: 1em;
background: #ccc;
border-radius: 5px;
`
return (
<Button>{children}</Button
)
}
App.tsx
import React from 'react'
import styled from 'styled-components'
export default function App() {
return (
{/* This button would render with the default styles from Button.tsx */}
<Button>Button One</Button>
{/* This button would render with extended styles, a blue background for example */}
<Button>Button Two</Button>
)
}

In your App.tsx you can do the same:
const BlueButton = styled(Button)`
background: blue;
`
what styled-components does is it creates a class with background blue and pass it to your Button. so in your Button.tsx you need to accept the css class
export default function Button({ className, children }: IButton) {
const Button = styled.button`
padding: 1em;
background: #ccc;
border-radius: 5px;
`
return (
<Button className={className}>{children}</Button
)
}
Edit
another way to do is to export the style like this
const BaseStyles = css`
padding: 1em;
background: #ccc;
border-radius: 5px;
`
const BaseButton = styled.button`
${BaseStyles}
`
Then later override the styles
const BlueButton = styled.button`
${BaseStyles}
background: blue;
`

Related

Is there any way I can style the nested component?

Here's my code.
/*Default Styled Component*/
import styled from "styled-components";
export const MenuWrapper = styled.ul`
border: 1px solid blue;
`
export const MenuList = styled.li`
color: blue;
`
export const Menu = (
<MenuWrapper>
<MenuList>1</MenuList>
<MenuList>2</MenuList>
<MenuList>3</MenuList>
</MenuWrapper>
);
/* This is where I tried to restyle */
import styled from 'styled-components';
import {
Menu,
MenuWrapper,
MenuList,
} from '../src/components/Menu.style';
const StyledMenu = styled(Menu)`
${MenuWrapper} {
border: 1px solid green;
}
${MenuList} {
color: green;
}
What I want to do is to create a default styled component with multiple elements in it and restyle according to my needs by using 'styled(Menu)' and adding ${MenuWrapper} ${MenuList} as selectors for nested elements but they all don't seem to work... Anyone can help..? Thank you in advance...
I see several issues here, but in the first place it seems like the problem is caused by the fact that you're not attaching the className prop to what's inside Menu.
See https://styled-components.com/docs/basics#styling-any-component and this Codesandbox: https://codesandbox.io/s/sweet-carlos-vt165s

Access props inside the styled component using MUI

I'm trying to create a custom button component using MUI on a React JS project. I've checked the docs and I discovered that I can do this using styled components. All worked well with the code presented below. The problem is that I want to create a more "customizable" component. I have inside my theme file 2 sets of colors (primary and secondary). The fact is that I want to create a button that is able to take a prop for this set of colors (primary / secondary).
import * as React from 'react';
import ButtonUnstyled, {
buttonUnstyledClasses,
ButtonUnstyledProps,
} from '#mui/core/ButtonUnstyled';
import { styled } from '#mui/system';
import { theme } from '../../theme';
const CustomButtonRoot = styled('button')(`
background-color: ${theme.palette[props.type].main};
padding: 15px 20px;
border-radius: 10px;
color: #fff;
`);
interface TodoButtonProps {
unstyledProps: ButtonUnstyledProps,
type?: 'primary' | 'secondary'
}
function CustomButton(props: TodoButtonProps) {
return <ButtonUnstyled {...props} component={CustomButtonRoot} />;
}
export default CustomButton
The question is: How I can include this prop inside the styled component code?
Pass a callback. In this callback the first argument is the props of the styled component. You can also use the style object instead of template string. More detail in this answer.
const CustomButtonRoot = styled("button")(
({ theme, myColor }) => `
padding: 15px 20px;
border-radius: 10px;
color: ${myColor};
`
);
<CustomButton myColor="red">abc</CustomButton>

error:styled_components__WEBPACK_IMPORTED_MODULE_0__.default.FaChevronRight is not a function

**import styled from 'styled-components';
import { FaChevronRight } from 'react-icons/fa';
const ButtonSty = styled.button`
width:128px;
height:32px;
border:2px solid #074EE8;
box-sizing:border-box;
border-radius:4px;
`
const Ancor = styled.a`
font-style:normal;
font-weight:normal;
font-size:16px;
line-height:18px;
color:#074EE8;
text-decoration:none;
`
const Icon = styled.FaChevronRight`
width:4px;
height:9px;
border:2px solid #074EE8;
`
function Button() {
return (
<div>
<ButtonSty> <Ancor href="#">Saznaj vise **<Icon />**</Ancor> </ButtonSty>
</div>
)
}
export default Button**
Guestion: how to style a react-icon with styled-component
When i create Icon and put in ancor the error above show
I do not know how to style component with react-icon
The dot notation is for styling HTML elements, i.e. button, a, div, etc. The correct syntax for styling another React component is:
const Icon = styled(FaChevronRight)`
width: 4px;
height: 9px;
border: 2px solid #074EE8;
`
See: Extending Styles
This is a custom component, so you have to wrap it with parentheses:
const Icon = styled(FaChevronRight)`
width:4px;
height:9px;
border:2px solid #074EE8;
`

Styled component ReactJs

export const RedHeader = styled.div`
color: red;
border: 1px solid blue;
background-color: gray;
`;
function Header(className) {
return (
<RedHeader className={className}>
this is styled component example
<p>test</p>
</RedHeader>
)
}
export default Header;
I have red the cdocumentation but i can't figure out, why should we use className as a props and after that in className={className}?
When using styled components, there should be no need to use className (which renders as class attribute in HTML) anymore. In your example, you pass className to the styled component, but the styled component does not use it in any way.
You can pass properties to your styled components if you want dynamic styling like you would do with class names in classic CSS.
Example with style that depends on a class name:
const RedHeader = styled.div`
color: red;
&.active {
color: blue;
}
`
Example with props:
const RedHeader = styled.div`
color: ${props => props.active ? 'blue' : 'red'}
`
function Header({ active }) {
return (
<RedHeader active={active}>
example
</RedHeader>
)
}

styled-components causing unexpected behaviour when rendering props

I have a WhiteBox react component which simply renders a white box with some styles.
I have a SmallBox react component which simply uses WhiteBox to render a more specific box.
I have a Content react component which renders three SmallBox boxes which does what it's supposed to do (renders three white boxes).
However when I tried to add a text as a props from the parent, the white box is aligned with some unexpected margin from top.
NOTE: when I simply put "This is a text" the css is okay, but when I send "this is a text" as props.text, the whitebox is rendered with extra margin from top.
I Use styled-components and react as I said.
I've tried to console.log the text, and everything seems to be okay. I also tried to switch the props.children or props.text and it does not work
-----------------White Box Component ----------------------
import styled from "styled-components";
const StyledBox = styled.div`
display: inline-block;
width: ${props => props.width}px;
height: ${props => props.height}px;
margin-right: ${props => props.marginRight}px;
margin-left: 100px;
background-color: white;
border-radius: 5px;
font-size: 13px;
font-weight: 700;
text-transform: uppercase;
color: #646777;
padding: 10px;
`;
const WhiteBox = props => {
return (
<StyledBox
width={props.width}
height={props.height}
marginRight={props.marginRight}
>
{props.text} // if I change this to simply "this is a text" it works well. somehow the props.text is causing problems.
</StyledBox>
);
};
export default WhiteBox;```
-----------------Small Box Component ----------------------
import React from "react";
import styled from "styled-components";
import WhiteBox from "../whitebox/white-box";
const SmallBox = props => {
return (
<WhiteBox width={320} height={130} marginRight={70} marginLeft={70} text={props.text}>
</WhiteBox>
);
};
export default SmallBox;
-----------------Content Component ----------------------
import React, { Component } from "react";
import SmallBox from "./smallbox/small-box";
import styled from "styled-components";
const StyledContent = styled.div`
position: absolute;
left: 320px;
top: 80px;
width: 100%;
height: 100%;
background-color: #f1f3f7;
`;
class Content extends Component {
render() {
return (
<>
<StyledContent>
<SmallBox text="this text is great" /> // causing problem
<SmallBox />
<SmallBox />
</StyledContent>
</>
);
}
}
export default Content;
The issue has to do with how many lines are rendered. The longer the text in the props, the more the lines rendered.
One solution would be to change the display property for WhiteBox:
const StyledBox = styled.div`
display: inline-flex;
....
`;
Another solution would be to override the default style vertical-align: baseline, simply add vertical-align: top;
const StyledBox = styled.div`
display: inline-block;
....
vertical-align: top;
`;

Resources