How do I use a CSS module class in a function?
an example: I have the className {styles.item} but I want to use that within a function such as...
export default function MenuItem {
if(props.type == "extra"){
{styles.item}.classList.add("extra");
}
return (
<MenuItem name="test product" type="extra" />
);
}
I have tried using it just as styles, with {} and with ${}
So what I want to do is if the has a type of "extra" then I want to add a dashed border.
https://github.com/JedWatson/classnames
You can install this page and use it in your react app
npm install classnames or yarn add classnames.
The Css
.success {
color: green;
}
.error {
color: red;
}
The JS
import styles from './alert.module.css'
import cn from 'classnames'
export default function Alert({ children, type }) {
return (
<div
className={cn({
[styles.success]: type === 'success',
[styles.error]: type === 'error'
})}
>
{children}
</div>
)
}
<div className={`anyClass ${props.type==='extra' ? 'extra' : null}`}/>
styles.item is a string (a class name).
It's not clear what you're trying to do with {styles.item}.classList.add( ... ).
If you want to further distinguish "extra" from "item" you should add an additional class to your stylesheet and pass them both:
<MenuItem className={`${styles.item} ${styles.extra}`} />
There are libraries like clsx to help with conditionally assembling class names:
const classes = clsx(
styles.item,
{
[styles.extra]: props.type === 'extra'
}
);
<MenuItem className={classes} />
You can use it in a function just like any other string or variable:
function Foo () {
// nothing special about styles.item. it's just a string.
const classes = props.type === 'extra'
? `${styles.item} ${styles.extra}`
: styles.item;
return classes;
}
Say you had the following function:
const getStyleClass = () =>
if (condition){
return "one"
} else {
return "two
}
You could use the function like so:
<MenuItem name="test product" type="extra" className = {() => {getStyleClass()}}/>
Keep in mind however, that the function will be called once and updating the css class dynamically will require a bit more work
Related
In my nextjs-app, I have a component where I want to add conditional styling.
So I have made a component-level stylesheet MyComponent.module.css, which has:
.primary {
color: blue;
}
.secondary {
color: orange
}
Then, in my component, I tried to do this:
import styles from "./MyComponent.module.css"
export default function MyComponent({ text, type }) {
return (
<button className={`${type === "primary" ? styles.primary : styles.secondary}`}>
{text}
</button>
)
}
but this doesn't work e.g. returns undefined
So, how can I solve this?
Try removing the backticks.
import styles from "./style.module.css";
const App = () => {
const type = "primary";
const text = "Hello"
return (
<div className={type === "primary" ? styles.primary : styles.secondary}>
{text}
</div>
);
};
export default App;
What is the best way to achieve this behavior along with React + TypeScript?
import { Button, Card } from 'src/components';
const Page = () => (
<div>
<Card mx3 p3 flex justifyContentEnd>
/* Card content */
</Card>
<Button my2 mx3>
Login
</Button>
</div>
);
For instance, mx3 will add 16px margin horizontally, my2 will add 8px margin vertically, etc., similar to how the Bootstrap framework uses classes to apply utility styles easily.
I have looked through a few component libraries with this sort of behavior in order to find a suitable solution; however, I find most do not have strong typing support. Examples are RNUILib, NativeBase, Magnus UI, etc.
You can declare your props like that:
const styles = ['mx3', 'p3', 'flex'] as const
type Styles = Record<typeof styles[number], boolean>;
Then use them like this:
type CardProps = Styles & {
other: 'props here'
}
Now, this should work:
<Card mx3 p3 flex />
You can get applied props like this:
const values = Object.entries(props).map(([key, value]) => value ? key : null).filter(Boolean)
If you see the source code of react-bootstrap, they have mapped the boolean to some CSS class using a util function of classnames package. You can do the same:
...
...
<Component
{...buttonProps}
{...props}
ref={ref}
className={classNames(
className,
prefix,
active && 'active',
variant && `${prefix}-${variant}`,
size && `${prefix}-${size}`,
props.href && props.disabled && 'disabled',
)}
/>
...
...
I have the following component which map over an array and display a set of buttons which they render specific content:
export const Bookings = ({bookings}) => {
const [selectedBooking, setSelectedBooking] = useState(false);
const handleSelectedBooking = (id, destination) => {}
const handleToggleButton = () => {
setSelectedBooking(!selectedBooking)
}
return(
<div>
{
bookings.map(booking => (
<button
className={selectedBooking ? 'selectedBooking' : 'notSelectedBooking'}
onClick={() => {
handleSelectedBooking(booking.id, booking.destination)
handleToggleButton()
}}
>
{booking.destination}
</button>
))
}
</div>
)
}
Where I have these styles already defined but somehow the styles are not applied, did I miss anything?
You have a typo in your ternary operator. It should be selectedBooking instead of selectedBoking.
Did you import styles file in the current file, where you write your component?
Moreover, I recommend you using modules to set styles in your component. How this works: you name your css file like this MyStyles.module.css (.module is obligatory) and then import in React component file these styles like import styles from './MyStyles.module.css'. Then you set styles in jsx code like this: className={selectedBoking ? styles.selectedBooking : styles.notSelectedBooking}.
This approach makes classnames unique across all the project even though they have the same names in different css files.
I want to create a, b, div or another element based on as={""} prop in my function.
I am checking as and then use if guards to create element one-by-one. But is there any way to create html element based on as component?
I want to be able to create b, a, h4 h3 or any element without if's
I've found similar question but it uses styled components. Is it possible to do it without it?
Currently im doing this:
import * as React from 'react'
interface Props {
children: (React.ReactChild | React.ReactNode) | (React.ReactChild[] | React.ReactNode[])
onClick?: (e) => void
as?: string
}
const DynElement: React.FunctionComponent<Props> = props => {
const { as , children } = props
return (
<>
{as === 'div' && <div {...props_rest}>
{children}
</div>}
{as === 'b' && <b {...props_rest}>
{children}
</b>}
</>
)
}
export default DynElement
and usage is:
<DynElement as="b" onClick={...}>...</DynElement>
Using TypeScript + React.
Capture the as prop in an uppercase variable and use that as a JSX component:
const { as: Cmp = ‘div’, ...rest } = props;
return (
<Cmp {...rest} />
);
No need to even pass children explicitly. It will be passed along with the ‘rest’ props.
So I'm making a todo list app and to provide alternate colors to new todo items as they are added in the todolist i have used the if else statement in React component but i think it is not evaluating.
Below are the two classes from my css file that i'm using -->
.bgColorItem1{
background-color: white;
}
.bgColorItem2{
background-color:grey;
}
Below is the component that accepts arguments item(todo item that will be added to the list) and key(index passed as key) from todolist -->
import React from 'react';
import './App.css';
const TodoItem=({item,key})=>{
let settingClass="";
// *****so the problem is here in the if condn that's not putting settingClass as bgColorItem1*****
if(key%2===0){
settingClass="bgColorItem1";
}else{
settingClass="bgColorItem2";
}
return <div className={`boxSpace centerAligning ${settingClass}`}>{item}</div>
}
export default TodoItem;
So what i expect from this code that key which was index in todolist component passed to todo here above should return 0 for even so that settingClass can have alternate values and hence provide alternate colors.But that is not the case.
First of all, don't use key's value since it is internal. Secondly, you can achieve like this
{items.map((item, index) => <TodoItem item={item} index={index} />)}
In TodoItem
const TodoItem=({ item, index })=>{
let settingClass=index % 2 === 0 ? 'bgColorItem1' : 'bgColorItem2';
return <div className={`boxSpace centerAligning ${settingClass}`}>{item}</div>
}
However, you don't need react to do this, just use css, in your css
.boxSpace:nth-child(odd) {
background: red;
}
.boxSpace:nth-child(even) {
background: blue;
}
You can't use key property as it is reserved, also you will get a warning for it:
Warning: ListItem: key is not a prop. Trying to access it will result in undefined being returned. If you need to access the same value within the child component, you should pass it as a different prop.
Simple example:
const ListItem = ({ key }) => {
console.log(key);
return <div>{key}</div>;
};
const App = () => {
return (
<>
{[0, 1, 2, 4].map(item => (
<ListItem key={item} />
))}
</>
);
};
Your TodoItem component shouldn't have to care about the key prop, but rather a boolean (or a string if you have more than 2 styles) prop like alternateStyle:
const TodoItem=({item,alternateStyle})=>{
return <div className={
`boxSpace centerAligning ${alternateStyle ? 'bgColorItem2' :
'bgColorItem1'}`
}>
{item}
</div>
Then you can set the value you need to alternateStyle in the parent component:
<div>
{items.map((item, index) => <TodoItem item={item} alternateStyle={index % 2 !== 0} />)}
</div>
key "prop" is reserved in React. You cannot use it. Rename this props to "idx"
See: Special props