I'm starting to work on a react components library and I want to reuse some SCSS code we share with other non-react projects.
To accomplish that, I'm trying to use SASS modules into react component.
The simple use case works fine, but I'm creating a components library and I need to have several style combinations for some components like the button.
Right now, I'm having an issue with the Button component. Component is pretty simple, but it has 3 different variant values.
Here is the Button.tsx file:
import React from "react";
import styles from "./Button.module.scss";
type Variant = "default" | "primary" | "tertiary";
interface Props {
children: String;
variant: Variant;
}
export const Button: React.FC<Props> = ({ children, variant }) => {
return <button className={`${styles.button} ${variant}`}>{children}</button>;
};
and here is the Button.module.scss file:
.button {
border: none;
padding: 0.5rem 1.5rem;
border-radius: 0.25rem;
background-color: grey;
color: white;
&.default {
background-color: green;
}
&.primary {
background-color: red;
}
}
What I expect, is to have a green button if I use the component like <Button variant="default">I'm green</Button>, but instead I'm getting the grey button.
Here is a live example on codesandbox
I'm stuck on this, could somebody help me to apply different styles based on prop values?
<button className={`${styles.button} ${styles[variant]}`}>
Please use classnames npm library.
import cn from 'classnames';
<button className={cn(styles.button, styles[variant])}>
Related
I'm building a component library using React, TypeScript, Styled Components, and Rollup. Now I've created a Button component using a type interface. I then roll up the library to install it locally in my test project. I then import the Button and try to use it. I have defined two props for the button: children and type. Children is of type React.ReactNode, and type is of type String. Now when I use the Button component in my test project is keeps saying the following:
Type '{ children: string; type: string; }' is not assignable to type 'IntrinsicAttributes & ButtonProps'.
Property 'children' does not exist on type 'IntrinsicAttributes & ButtonProps'.
Below is my type interface for the Button:
import React from "react";
export type ButtonProps = {
type: String;
children: React.ReactNode;
};
And below if my Button:
import React from "react";
import { ButtonBase } from "./button.style";
import { ButtonProps } from "./button.types";
function getButton(type: String) {
switch (type) {
case "base":
return ButtonBase;
default:
return ButtonBase;
}
}
const Button = ({ type, children }: ButtonProps) => {
const Component = getButton(type);
return <Component>{children}</Component>;
};
export default Button;
And this is how I then use the Button in my test project:
import { Button } from "aab-react-emerald";
function App() {
return (
<div className="App">
<header className="App-header"></header>
<Button type="base">Button</Button>
</div>
);
}
This is my ButtonBase. It is a Styled Component which inherits some styling from a basic Button component. There will be two more buttons, which both will inherit some default styling.
import styled from "styled-components";
import theme from "#theme";
const Button = styled.button`
display: flex;
justify-content: center;
align-items: center;
border: none;
padding: 8px 16px;
height: 40px;
box-shadow: none;
font-size: 16px;
line-height: 24px;
border-radius: 2px;
cursor: pointer;
transition: background-color ${theme.transition};
transition: ${theme.transition};
`;
export const ButtonBase = styled(Button)`
color: white;
background-color: ${theme.colors.g300};
:hover {
background-color: ${theme.colors.g200};
}
:active {
background-color: ${theme.colors.g400};
}
`;
Does anyone know what I should do differently?
I've seen a comment where children should be defined as children: React.ReactNode | string; But this should not be used as ReactNode also include type of string as an argument and is also a bad practice.
Additionally these types are inferred by the HTML Element of Button. So they do not need to be specified.
export type ButtonProps = {
type: String;
children: React.ReactNode;
};
Another way of writing your styled button component that you may want to explore could be of
const Button = styled.button<
React.ComponentProps<'button'> & React.HTMLAttributes<HTMLButtonElement>
>`
display: flex;
justify-content: center;
align-items: center;
border: none;
padding: 8px 16px;
height: 40px;
box-shadow: none;
font-size: 16px;
line-height: 24px;
border-radius: 2px;
cursor: pointer;
transition: background-color ${theme.transition};
transition: ${theme.transition};
`;
Your implementation appears correct.
In this code here
<Button type="base">Button</Button>
'children' is in fact a string, not a ReactNode - that's why it's getting rejected, the types don't match. If you allow a string in your type definition that should fix it:
children: React.ReactNode | string;
You can define the component with the React.FC type, which adds the children prop to the props. For example:
import React from "react";
import { ButtonBase } from "./button.style";
import { ButtonProps } from "./button.types";
function getButton(type: String) {
switch (type) {
case "base":
return ButtonBase;
default:
return ButtonBase;
}
}
// Using FC there's no need to add the children props into ButtonProps
// as it is already defined in the FC.
const Button: React.FC<ButtonProps> = ({ type, children }) => {
const Component = getButton(type);
return <Component>{children}</Component>;
};
export default Button;
Here you have an interesting explanation about the React.FC type!
I am a junior developer who just started working in a company.
I have a bit of experience in React and could not solve the current situation.
The situation i am having a trouble with is that when I import from the library that I have distributed in npm, my React project cannot recognize the styled components.
I get this error on my project.
enter image description here
I have researched and realized that the babel needs more options such as using
"babel-plugin-styled-components" option.
Unfortunately, this did not work after using the command and distributed with the commands
yarn build == webpack --mode production
Is there anyway that I can use styled-components library??
thank you!
P:S: I think I need to put more information.
Many people thankfully answered my question but I tried them and I got an another error.
enter image description here
P.S:
My file structure:
enter image description here
My code of Button
export const StyledButton = styled.button`
background-color: white;
border-radius: 3px;
border: 2px solid palevioletred;
color: palevioletred;
margin: 0.5em 1em;
padding: 0.25em 1em;
${props => props.primary && css`
background: palevioletred;
color: white;
`}
`;
export default class Button extends React.Component {
constructor(props) {
super(props);
console.log("Props:", props);
}
render() {
return (
<div>
<StyledButton>{this.props.children}</StyledButton>
{/* <button> {this.props.children} </button> */}
</div>);
}
}
My index.js of Button
import Button from "./Button";
export default Button;
My index.js of src folder
export * from "./components";
My babel.config.js
module.exports = function BabelConfigJS(api) {
api.cache(true);
const presets = ["#babel/preset-env", "#babel/preset-react"];
const plugins = [
"styled-components",
[
"#babel/plugin-transform-runtime",
{
corejs: 2,
helpers: true,
regenerator: true,
useESModules: false,
},
],
[
"#babel/plugin-proposal-class-properties",
{
loose: true,
},
],
];
return {
sourceType: "unambiguous",
presets,
plugins,
};
};
PS: Error code
enter image description here
enter image description here
enter image description here
The error (which really is just an Eslint complaint) does not refer to using styled-components at all!
It's just saying components should be in PascalCase, not camelCase as you have now.
That is, instead of <styledComponent />, it'd be <StyledComponent />.
You just need to change the component name to be Uppercased, it has nothing to do with babel, etc.
// not <styledButton/>
<StyledButton/>
It is a requirement from React as in JSX lower-case tag names are considered to be HTML tags.
Hi I'm new to vue and am trying to understand its one-way data bind model component registration and passing props.
In my index.js I have my parent component in which I want to render a single child right now
import Vue from 'vue'
import StyledTitle from './components/StyledTitle'
new Vue({
el: '#app',
components: {
StyledTitle,
},
})
Child Component is StyledTitle.js
import Vue from 'vue'
import styled from 'vue-styled-components'
const StyledTitle = styled.h1`
font-size: 1.5em;
text-align: center;
color: #ff4947;
&:hover,
&:focus {
color: #f07079;
}
`
Vue.component('styled-title', {
props: ['text'],
components: {
'styled-title': StyledTitle,
},
template: `<StyledTitle>{{ text }}</StyledTitle>`,
})
export default StyledTitle
Finally my HTML is which I expect to render a red Hi
<div id="app">
<styled-title text="Hi"></styled-title>
</div>
The HI is not showing up though and the props value is undefined. Coming to this from react so wondering why this isnt working, thanks!
Ps screenshot of my vue devtools
The issue is that your StyledTitle.js file exports a normal styled <h1> component which uses a default slot for its content instead of your custom component that accepts a text prop.
If you're still keen on using a prop-based component, you need to export that instead of the one from vue-styled-components. You should avoid global component registration in this case too.
For example
// StyledTitle.js
import styled from 'vue-styled-components'
// create a styled title locally
const Title = styled.h1`
font-size: 1.5em;
text-align: center;
color: #ff4947;
&:hover,
&:focus {
color: #f07079;
}
`
// now export your custom wrapper component
export default {
name: 'StyledTitle',
props: ['text'],
components: {
Title, // locally register your styled Title as "Title"
},
template: `<Title>{{ text }}</Title>`,
})
Given your component doesn't maintain any state, you could make it purely functional. Using a render function will also help, especially if your Vue runtime doesn't include the template compiler (which is the default for most Vue CLI apps)
export default {
name: 'StyledTitle',
functional: true,
props: { text: String },
render: (h, { props }) => h(Title, props.text)
}
I am using the awesome "Styled-Components"
but I am now using another package that wraps an element inside it so I can't push my StyledComponents there as I don't want to change his package.
I saw glamor has a nice trick.
Is that supported with StyledComponents?
import { css } from 'glamor';
let rule = css({
color: 'red',
})
<div {...rule}>
zomg
</div>
If you think about why I need it, here is an example:
this is an external package I'm using:
External = props => (
<div>
<input style={props.inputStyle} className={props.inputClass} />
</div>
);
so you can see I need to pass in a json style or className
so Glamor will work here, but I dont want to use it just for this scenario.
I'm already enjoying StyledComponent
Thanks
If I understood your query, you can define css rules to a component, like this
import styled from 'styled-components'
const Wrapper = styled.div`
color: 'red';
font-weight: bold;
background-color: ${ props => props.color === 'primary' ? 'green' : 'red' }
`
export const Component = () => {
<Wrapper color='primary'>
I have a red text, and bold font-weight.
</Wrapper>
}
I am using reactjs and trying to get me css inside javascript and finally read the css from an external js file.
Here is the code:
import React from 'react';
import ReactDOM from 'react-dom';
var styles = {
container: {
padding: 20,
border: '5px solid green',
borderRadius: 2
}
};
var myComponent = React.createClass({
render: function() {
return (
<div style={styles.container}>
{this.props.name}
</div>
);
}
});
This works fine but what I need to do is to put the css in an external file.
So I've created a file called general.css.js
And I tried to import it:
import styles from './components/general.css';
I add this import to the top of the page with the other imports.
The problem is that it's not reading the styles.
What I'm I doing wrong here?
Make a new file and put this code in it.
export const style = { container : {
padding: 20,
border: '5px solid green',
borderRadius: 2 }
};
Now in your component file.
import * as styles from './style/location/filename'
Now you can use styles in your render function.
return (
<div style={styles.style.main}>
<h3 style={styles.style.header}>Vote for your favorite hack day idea</h3>
</div>
);
You can directly import your css file in js.
import './style/app.css';
app.css
.page {
background-color:#fafafa;
}
and you can use this class in React component like below.
<div className="page">
Hope it works!!!!
There is a little tool that automates translation from CSS to JSON representation.
Worth checking that out.
Note how the translation adds _ underscores:
div.redcolor { color:red; }
div:hover { color:blue; }
Into:
{"div_redcolor":{"color":"red"},"div_hover":{"color":"blue"}}
Note how the Vishwas Chauhan used starred method of ES6 import export:
In case you use this tool you get one big object, and you can use any method.