'Box' component vs css prop for layout, what to choose? - reactjs

I'm using styled-system and Emotion now and I can't come to an understanding of which approach is more correct to use. I have some "Box" component, which handles different props like mx, my, px, py, bg, color, and many others from https://styled-system.com/api/.
Sometimes I have the following situations :
I have some "Select" component, which doesn't have styled-system props. And I have to add some margins (for example) to this Select. I can do this in following ways :
import {Select} from 'Select'
<Box
as={Select}
my={32}
ml={10}
/>
Or I can use Emotion's css prop with #styled-system/css and do next :
/** #jsxImportSource #emotion/react */
import {Select} from 'Select'
import css from '#styled-system/css'
<Select
css={css({
my: 32,
ml: 10
)}
/>
For me personally, the css option seems more readable, but I already use the "Box" component in many places of the project and I do not know whether to change their syntax or not.before :
<Box mx={1}/>
after :
div css={css({mx=1})}
Which option in which situation would be more correct?

This is pretty subjective. Your box is not the same as a div. Presumably, you have a border-box rule for the Box component. Let's not get the whole reason for using the box confused. If you just want your select to have all the props of a box, well, it should already have that, assuming your Select definition looks like this
const Select = ({ onClick, ...styleProps }) => <Box {...styleProps}><p>select me</p></Box>
export default Select

Related

How can I set the Overlay container property when using OverlayTrigger?

I'm using the OverlayTrigger component to get hover behavior for tooltips, and therefore not using the Overlay component directly. The Overlay component has a container property that I'd like to use to remedy the tooltip getting cut off by its natural container element.
I've attempted to pass a popperConfig object, but that's not working. I've also tried adding a container attribute to the OverlayTrigger component.
<Container fluid className='flex-fill' ref={rowContainer}>
...
<OverlayTrigger delay={{show: 500}} overlay={renderUserTooltip}
popperConfig={{container: rowContainer}}>
<FaUser/>
</OverlayTrigger>
How can I set the container for the Overlay when the Overlay component isn't directly used?
React bootstrap doesn't have a container prop or something similar (I mean it has a target prop but as this part of the docs suggests, for the OverlayTrigger the type is null, so it doesn't accept values and I don't think you can trick it to accept (and I don't think it would be wise to try).
But a pretty nice example, that shows some sort of a workaround in my opinion, can also be find in the docs, under customizing-trigger-behavior.
Starting from that example, if you need your trigger to be totally separated from the container an option is to just wrap everything in a big container that receives ({ ref, ...triggerHandler }) and all is left is to give your container the ref, and the trigger to your FaUser component. So something like:
<OverlayTrigger
placement="bottom"
overlay={<Tooltip id="button-tooltip-2">Check out this avatar</Tooltip>}
>
{({ containerRef, ...triggerHandler }) => (
<Container fluid className='flex-fill' ref={containerRef}>
...
<FaUser/>
</Container>
)}
</OverlayTrigger>
I also created a sandbox with a minimal reproducible example.

Check If Prop Exists in Styled Components

I am just getting started with styled components and want to create variations for things like buttons, navbars, etc.
For instance, I'd like to create a dark version of a navbar (wherein the background color would become dark and the text color light).
What I'd like to do is simply add a prop of dark on a component as follows:
<Navbar dark>...</Navbar>
I'd like to do this as opposed to something like this:
<Navbar type="dark">...</Navbar>
However, I'm not sure how to do this. That is, how do I style an element just by checking if the prop name exists (without passing the prop any values)?
Any ideas? Thanks in advance.
styled-components supports passing props to styled components, and those props can be accessed in the CSS tagged template literal (the CSS inside of the backticks) of the styled component receiving those props.
For example, say that the <Navbar /> in your example is a styled <nav> element, then we can define <Navbar /> in a way that takes into account a dark prop:
const Navbar = styled.nav`
background: ${props => props.dark ? 'black' : 'white'}
`
In the example above, we check for the existance of the dark prop. If it was passed, then we give the component a black background color. Otherwise (the default), we give the component a white background color:
<Navbar dark /> // produces component with black background
<Navbar /> // produces the default white background

How to pass padding/margin as props in React-Bootstrap components

I am trying to apply margins and paddings with React-Bootstrap as props.
I passed the docs through but haven't found any mention adding padding or margin in there as it is in official bootstrap docs (3th and 4th). I know it doesn't support well Bootstrap 4, so tried with both.
I tried to pass params as p={1}, paddingxs={5} or mt='1' but it doesn't recognize any of them. More over tried to find any Spacing element in React-Bootstrap folder, but failed.
Paddings and margins work as classnames. But I feel there must be a way to it without Bootstrap classes. There must be a kind of property.
First include bootstrap CSS in your src/index.js or App.js
import 'bootstrap/dist/css/bootstrap.min.css';
Then you can style your component by passing desired bootstrap CSS class name as className prop in React, for example:
import React from "react"
import Container from "react-bootstrap/Container";
function MyComponent() {
return (
<Container fluid className="p-0">
<SomeOtherComponent />
</Container>
);
}
export default MyComponent
Above code will add p-0 CSS class to Container.
Reference
React - How do I add CSS classes to components?
React-Bootstrap - Stylesheets
You can add margin and padding by using default React's style:
const divStyle = {
marginLeft: '10px',
};
function HelloWorldComponent() {
return <div style={divStyle}>Hello World!</div>;
}
Refrenced from here
The answer is: there is no props from React Bootstrap to use margins/paddings.
You can use props for col class, but no for margins.
Example:
<Col className="col-6 col-md-3 mb-3 pt-2">
// there you have a Col component from React-Bootstrap 4
// it has some grid system classes, that you can use as props like this:
https://react-bootstrap.github.io/layout/grid/
<Col xs={6} md={3} className="mb-3 pt-2">
// but as you can see, the native classes of Bootstrap 4 like
// mt, mb, pt, pb etc, they have not a props use with
// React-Bootstrap, you have to use them like regular classes
// inside "className"
You'll want to add className="p-5" to the element. This isn't documented in react-bootstrap but it's in the original Bootstrap 4 documentation here: https://getbootstrap.com/docs/4.4/utilities/spacing/#examples
Usually, I'm able to add custom styles to React Bootstrap components by just adding them to the style param. I've put together a short example below, hope this helps.
import React from 'react';
import { Button } from 'react-bootstrap';
const styles = {
myCoolButton: {
paddingTop: "10vh",
paddingBottom: "10vh",
paddingRight: "10vw",
paddingLeft: "10vw"
}
}
const ReactButton = (props) => {
return (
<Button style={styles.myCoolButton} onClick={()=> {
console.log("Do something here!")
}}>Click Me!</Button>
);
}
export default ReactButton
You can also pass custom components (including those from react-bootstrap) into the styled-components constructor if you prefer to do it that way.
None of the jQuery-free implementations of Bootstrap (React Bootstrap, BootstrapVue or ngBootstrap) have implemented utility directives for spacing (margin/padding), simply because Bootstrap have made it unnecessary in the vast majority of cases, by providing a very intuitive set of Spacing utility classes.
All you need to do is apply the desired class.
To apply utility classes selectively, based on responsiveness interval (media queries), you could use a useMedia hook, as demoed here.
In a nutshell:
const interval = useMedia([
"(min-width: 1200px)",
"(min-width: 992px)",
"(min-width: 768px)",
"(min-width: 576px)"
],
["xl", "lg", "md", "sm"],
"xs"
);
(Based on useMedia from useHooks/useMedia).
You can now reuse this hook throughout your app to add media interval based logic.
Example usages:
// interval === 'sm' ? a : b
// ['xs', 'sm'].includes(interval) ? a : b
// negations of the above, etc...
Important: this particular implementation returns the first matching media query in the list.
If you need to map various media queries, to an object/map with true/false values, you'll need to modify getValue fn to return the entire list, along these lines:
const getValue = () => {
const matches = mediaQueryLists.map(mql => mql.matches);
return values.reduce((o, k, i) => ({...o, [k]: matches[i]}), {})
};
Working example here.
Obviously, you could expand on it and add/remove queries. However, be warned each query adds a separate listener so it could impact performance.
In most cases, the return of the first matching query (first example) is enough.
Note: if the above useMedia hook is not enough for your use case, a more robust and heavily tested solution for media-query listeners in JS is enquire.js. It's easy to use, incredibly light and thoroughly tested cross-browser/cross-device. I have no affiliation with it, but I have used it in various projects over the course of more than a decade. In short, I couldn't recommend it more.
Back to Bootstrap 4: in order to customize the $spacer sizes, follow the guide provided under Bootstrap's theming as it's actually about more than what we typically call theming (changing colors), it's about overriding default values of Bootstrap's SASS defaults, including responsivenss breakpoints, spacers, number of columns and many, many others. The one you're interested in is $spacer.
Simply write the overrides into an .scss file and import it in your root component. Example.
Note: a (simpler and more intuitive) option to customize Bootstrap is to do it visually, using bootstrap.build but it's typically a few minor versions behind (i.e. Bootstrap is now at v4.4.1 and the build tool is at v4.3.0).
The build customizer provides intuitive controls and real time visualization.
It allows export as .css or .scss.
Just try this out once according to your input and still if face any issue you can reach out.In below we have increased the .col padding with .px-md-5 and then countered then with .mx-md-n5 on the parent .row.
JSX:
import React from 'react'
import { MDBContainer, MDBRow, MDBCol } from 'mdbreact';
const SpacingPage = () => {
return (
<MDBContainer>
<MDBRow className="mx-md-n5">
<MDBCol size="6" className="py-3 px-md-5">Custom column padding</MDBCol>
<MDBCol size="6" className="py-3 px-md-5">Custom column padding</MDBCol>
</MDBRow>
</MDBContainer>
)
}
export default SpacingPage;
If you still have any kind of doubt on this then feel free to ask .

How can I access to change styles of inner items of a component in react and material ui?

How can I access to inner css classes of children of a component and add or change styles to/of them? like I want to change and customize material ui stepper steps circle font size and color and so on.
How can I write css classes like bellow:
.stepper circle {
font-size:18px;
}
or
.stepper .text {
font-size:18px;
}
thanks.
Thanks to #spakmad's answer, but that's not exactly what I meant, maybe my question was not clear enough. I meant how to write above mentioned CSSs in material ui object style classes format(classes injected with withStyle HOC).
I found my solution:
stepper:{
'& circle':{
fontSize: '18px'
}
}
and
stepper: {
'& .text': {
fontSize: '18px'
}
}
The very straightforward way to do it without having to worry about classes is by using the material-ui style prop. Like so,
<Stepper style={{ fontSize: '18px' }} />
This applies a style to the root element, which I assume to be a div or container of sorts, although it probably varies by the component.
More specifically, and what you probably want to do is use material-ui classes prop. That is, since you know exactly what classes you want to override, you can do so as follows,
<Stepper classes={{ text: { fontSize: '18px' }}} />
I use text here as a classname because in the question, .text appears to reference and already existing class. Since you're trying to increase the size of the font in this svg that comes with the Stepper. You'll need to get the class name applied to the svg and override it. In this case, one of its classnames is MuiSvgIcon-root-184 so you would expect to be able to do,
<Stepper classes={{ MuiSvgIcon-root-184: { fontSize: '18px' }}} />
This classname however is generated by material-ui dynamically based on the layout resulting from props and could be different across all renders.
TLDR
So, trusty className component and writing some css and component JSX as follows.
<Stepper className={'customStepper'} />
.customStepper svg: {
font-size: '18px !important',
}
You need to include !important to make sure this style is respected. Material UI by default puts its styles last in the document so they're normally overwriting anything else, but the !important spec should override the override.

Material UI inline style not working

In Material UI, I want to set borderRadius on my buttons. Passing the style attribute seem to work for FlatButton but not for RaisedButton.
For RaisedButton, the borderRadius is applied to the parent <div> (which is necessary) but not to <button> itself (which is also necessary)
Is this a bug in Material UI? Or is this behaviour intended? If it's intended, then how do I make a RaisedButton with rounded corners?
import React from 'react';
import RaisedButton from 'material-ui/lib/raised-button';
import FlatButton from 'material-ui/lib/flat-button';
export default class MyButtons extends React.Component {
render() {
return (
<div>
<FlatButton label="flat button" style={{borderRadius: '25px'}}/> {/*works*/}
<RaisedButton label="raised button" style={{borderRadius: '25px'}} /> {/*does not work*/}
</div>
);
};
}
This is the intended behaviour, and says so in the docs. For the record, you would never want a style prop to be passed to multiple children as no styles would make sense across all children - and how deep in nesting would you apply them?
But I think you're mixing concerns here. Using style on a component should only ever effect the root element - and that's assuming the developer chose to pass along the style tag, which they did.
But what you're looking to do is not style the component, but style the elements of the component. What you want to do is use a CSS class:
<RaisedButton label="raised button" className="raised-button--rounded" />
.raised-button--rounded,
.raised-button--rounded button {
border-radius: 25px; /* assuming one is not already defined */
}
NB: The developers do not intend for you to change the component styles that they have not specifically exposed. Through this approach, you will run into issues eventually.

Resources