How to style React component with TailwindCSS - reactjs

I'm using TailwindCSS in a React Project. I'm able to style normal HTML elements by passing TailwindCSS utility classes in the className attribute but this doesn't work when I pass the utility classes inside a components className attribute like this:
<Dropdown className="hidden sm:block sm:ml-6"/>
Dropdown is a React component imported into another component.
How do I make this work?

if <Dropdown/> is your custom made component you probaly forgot to include in on the div inside your component definition,
you can rename "className" to customclass and apply it inside your component definition.
so with that your code would look like
<Dropdown customclasses="hidden sm:block sm:ml-6"/>
and your component definition,
const Dropdown = ({ customclasses, ...otherProps }) => <div className={customclasses}></div>
or if you dont want to change className you can spread the ...otherProps directly on the div
const Dropdown = ({ yourprop, yourprop , ...otherProps }) => <div {...otherProps}></div>

Related

How to properly join tailwind css classes using clsx?

I am trying to join tailwind classes and apply them to a button using clsx. One class is applied by default 'rounded-none' and the other one is passed in as a prop
const Button = ({
children, ...props
}): JSX.Element => {
return (
<ADButton
className={clsx('rounded-none', props.className)}
{...props}
>
{children}
</ADButton>
);
};
Let's say I have added padding-top: 0px; to the button like shown below
<Button
color="primary"
className="pt-0"
>
{t('btn.add')}
</Button>
The joined className should look like 'rounded-none pt-0'. If no className prop is passed, then just apply ‘rounded-none’
The problem am having right now is ‘rounded-none’ only gets applied to buttons without className prop. On buttons with className prop, only className prop gets applied but not ‘rounded-none’. How can I fix this so that both classes are joined and applied to the button?
You're having this issue because the default prop of ADButton is set to className and the extra prop you're passing to the Button component is set to className as well. In effect, you are overriding the default className with your newly passed className prop. If there are are 2 similarly named props, React will choose the one that is declared later in the event of a conflict.
So this:
<ADButton
className={clsx('rounded-none', 'pt-0')}
// I am declared later so I win
className='pt-0'
>
{children}
</ADButton>
becomes:
<ADButton
className="pt-0"
>
{children}
</ADButton>
Here's one solution:
const Button = ({
children, ...props
}) => {
const { classNameDestructured = "", ...rest } = props;
return (
<ADButton
className={clsx('rounded-none', classNameDestructured)}
{...rest}
>
{children}
</ADButton>
);
};
You destructure props and set a default for classNameDestructured. This allows you to declare Button without additional props:
<Button>
{t('btn.add')}
</Button>
Then you pass classNameDestructured as an argument to your clsx() function. Your additional classes are then joined and applied to the button.
This works because className isn't declared twice as a prop in ADButton anymore so we've eliminated the overriding conflict.
You could use a merge of clsx and twMerge twMerge to efficiently merge Tailwind CSS classes in JS without style conflict.
Be carefull to dont override your previous classes
import clsx, { ClassValue } from 'clsx'
import { twMerge } from 'tailwind-merge'
export const clsxm = (...classes: ClassValue[]) => twMerge(clsx(...classes))

How to access props inside react render return

I want to set the logo according to the selected theme. But I'm unable to do so as I'm fairly new to react. I am using class component. Do I need to define props function in the constructor?
This is what I've tried:
<Logo src={(props => props.theme.currentTheme === 'dark') ? logo_dark : logo_light} />
The code only seems to select light logo. I have used the same code in styling and it seems to work fine.
If its a class Component you should use this.props to access any props passed down to the class Component.

Why color appears as HTML attribute on a div?

This code works perfectly, it creates CSS classes with the corresponding color and applies the classes dynamically:
const Div = styled.div`
color: ${({ color }) => color};
`;
export default function Email() {
const [color, changeColor] = useState();
return (
<>
<Div color={color}>Email</Div>
{['red', 'palevioletred', 'blue', 'yellow'].map(x => <button onClick={() => changeColor(x)}>{x}</button>)}
</>
)
}
However, the color attribute appears in the DOM on the div element:
<div class="sc-crHlIS jxntNS" color="yellow">Email</div>
When I change the color prop name to something else like divColor it doesn't show as a DOM attribute. I understand that props appear as HTML attributes when they have the same name as a native HTML attribute, but color should not because it's not a valid HTML attribute.
Why this behavior?
Styled components has a set of HTML attributes that it allows to be passed down to the resulting element. The color attribute is not technically valid for a div element, however it is a HTML attribute, and this is the criteria it follows.
From the docs:
If the styled target is a simple element (e.g. styled.div), styled-components passes through any known HTML attribute to the DOM. If it is a custom React component (e.g. styled(MyComponent)), styled-components passes through all props.
The documentation does not explicitly state that they accept any attribute on any element, however it seems to be the case given this example:
<Div color="red" foo="foo" value="value" name="name" bar="bar">My div</Div>
Results in:
<div color="red" value="value" name="name">My div</div>
Notice how the non HTML attributes are removed, but the others remain.

when should I pass 'className' props to react component?

Some react components pass the className props to the child component.
I haven't seen any need for passing className as a prop in my projects.
why this className props is been used ? and when should i adopt this approach?
import styled from 'styled-components'
const ReactComponent = ({ className }) => {
return <div className={className}/>
}
const StyledComponent = styled(ReactComponent)``;
It really depends on the context, but generally, the className prop is passed down from parent to child to either overwrite, or append the existing className on the child component.
This is particularly useful in the scenario when you are building reusable base components which needed to be easily extended and customised.
Given your example,
const ReactComponent = ({ className }) => {
return <div className={className}/>
}
Let's say we have a parent component which renders the child ReactComponent, and we need to customise the stylings for this instance:
return (
<div className='container'>
<ReactComponent className='is-red' />
<ReactComponent className='is-blue'/>
</div>
)
This will allow the parent to render both components, with different styles, and without the need to repeat the same code.
You generally add classes to create a style or JavaScript code snippet that effects more than one element. Here is an explanation of how to use classes.
This particular component uses StyledComponent, but it's possible that the user wanted to add a class to add extra styles on top of those for the default in specific cases.
It's also possible that the classes are used to toggle some effect in JS. I've linked examples of each case.
Without more code it's hard to say why this particular user passed down a className, but there are certainly cases where you could want to, or when you could do without passing down a className. If your code doesn't seem to require it, there's definitely no reason to add it in.

How is it possible to make one component stand out from other same component in React

I was creating React project and I have component which is used in several places in the project. The question is how is it possible to make one certain different from other instances of that component in terms of css styling?
For achieving that you have to accept the styles of the component as props. And each time you use the component pass the desired style to each instance.
For example
const PopupHeader = ({ title, onClose, classes }) => (
<div className={classNames(styles.head, classes.header)}>
<span className={styles.headText}>
{title}
</span>
</div>
);
Here the PopupHeader component is receiving classes as props which is actually an object of styles passed from parent component, which is used in the child component.
Hope it helps.
You can use contextAPI for sending the styles in all components
<ParentComponent>
<Style.Provider value={{ style: "background: "white .. or something" }}>
{this.props.children}
</Style.Provider>
</ParentComponent>
You can send the styles in all child components

Resources