Set media query dynamically in Tailwind css - css

In my react js application i have a component where i want to set the mobile break pint according to a variable:
<Component size={'500px'}/>
const Component = ({size}) => {
return (
<div md:flex>hello</div>
)
}
I want to add instead of md:flex something like [size]:flex to be able to set break point according to that props.(ex: set display flex if the size is 500px or 100px or 900px) Question: Is there possible to set the mediaquery according to the way that i described above?

You could use classnames npm package:
const rootClassName = cn(
// you can add any tailwind classNames first
"h-full flex flex-col",
// this is conditional part. based on size prop, define className
{
[md:flex-1]: size === "A",
[sm:flex-1]: size === "B",
}
)

Related

multiple conditions for styling with Css modules

I am trying to set multiple conditions with ternary operator to style an element using Css modules. I can't find the exact syntax. is it even possible?
there are some boxes that have 3 sizes , their default small size, the big size for the one that's hovered, and the medium size when at least one of them is hovered.
import style from './styles.module.sass'
const Slider =()=>{
const [hover,isHovered]=useState(false);
const [anyCardHovered,setAnyCardHovered]=useState(false)
return
<div className={`{ hover? ${style.hoveredBox}: anyCardHovered? ${style.smallBox}: style.box}`>
</div>
<div className={hover
? style.hoveredBox
: anyCardHovered
? style.smallBox
: style.box
}></div>
Another way:
/* Bits: hover, anyCardHovered */
const classNames = [
style.box, // 00
style.smallBox, // 01
style.hoveredBox, // 10
style.hoveredBox // 11
];
<div className={classNames[hover << 1 | anyCardHovered]}>
</div>
More details in: https://blog.uidrafter.com/bitwise-table-lookup
I would probably create a variable called classes and set its value and logic above your JSX return statement. Then you could simply set classname={classes} in your boxes.
let classes = 'small';
if(hover) {
classes = 'big'
} else if (anyCardHovered) {
classes = 'medium'
} else {
classes = 'small'
}

Make a component with different sizes using SASS in React

I was always wondering how to make component with different sizes using SASS in React.
These are from airbnb, and let's assume these are same components.
The first one is 520px and the second one is around 130px.
If there exist these two sizes only, I know I can adjust the size using different className.
But what if I need different sizes more than two? like 300px, 400px and etc? Is it the only way to set className every time?
I could pass style prop to component, but it's CSS in JS so I think it becomes meaningless to use SASS.
How do others work with SASS in this kind of situation? I can't shift to Styled component now.
I would go with dynamic className and a prop size. Something like this:
const Button = ({ size, ... }) => {
[...]
return (
<button className={`button-${size}`}>
[...]
</button>
);
}
Button.propTypes = {
size: PropTypes.oneOf([
"small",
"regular",
"large",
]),
...
};
Button.defaultProps = {
size: "regular"
};
In you styles:
$buttonSizes: (
small: 300px,
regular: 400px,
large: 500px,
);
button {
#each $sizeName, $size in $buttonSizes {
&-#{$sizeName} {
width: $size;
}
}
}

filter icon in material-ui's v5 DataGrid

The default behavior for the new DataGrid is to hide a filter icon unless you hover over the column header (and have a filter applied). In the previous version the icon remained visible.
Codesandbox https://codesandbox.io/s/mui-datagrid-filter-icon-7rbrk
When a filter is applied it adds a new iconButtonContainer div. The classes are: MuiDataGrid-iconButtonContainer css-ltf0zy-MuiDataGrid-iconButtonContainer
Is there a way to override this behavior? All I'd like to do is set visibility to always be visible when that div is generated by the library.
The answer here was to create a separate styled component of the data grid and use the global classnames imported from mui to reference the correct one for the style you wish to override. In my case it was something like:
const MyStyledGrid = styled(DataGrid, () => ({
[`& .${gridClasses.iconButtonContainer}`] : {
visibility: "visible",
width: "auto"
}
}))
function MyComponent() {
return (
<MyStyledDataGrid {...props} />
)
}

In React,How to make a page that contains two dynamic size components

If data in container A collapses(minimised), Component B should increase vertically in size and appear on full page. Similarly if Component B is collapsed,component A should increase.By default,both the components have equal screen space.
there are tons of ways to do this, you can check how flexbox in CSS works. it should not bee very react specific, All you need to do from react is to know which component is collapsed and which is to expanded.
In the parent component, you'll want to track which component is maximised. Then, pass a maximised prop to component A and component B, and let them set their CSS classes based on it. You could hide most of the content if you just want a mini version of the component.
Assuming you're using function components with hooks, it would look somewhat like this:
const Container = () => {
// Either "A", "B" or null (equal sizes)
const [componentMaximised, setComponentMaximised] = useState(null);
return (
<div className="container">
<A maximised={componentMaximised === "A"}/>
<B maximised={componentMaximised === "B"}/>
</div>
);
};
const A = props => {
return (
<div className={props.maximised ? "component component-maximised" : "component"}>
// ...
</div>
);
};
const B = props => {
return (
<div className={props.maximised ? "component component-maximised" : "component"}>
// ...
</div>
);
};
You'll also want to pass the setComponentMaximised function to each component as a prop if you want them to be able to have a button to maximise and minimise themselves.
For your CSS, use display: flex in combination with flex-grow to set how the items share the space:
.container {
height: 100vh; /* approx full height */
display: flex;
flex-flow: column nowrap;
}
.component {
flex-grow: 1;
overflow: hidden; /* prevent contents from spilling out of component */
}
.component-maximised {
flex-grow: 3;
}
Quick demo of this technique (try changing the classes manually in HTML)
https://codepen.io/gh102003/pen/MWKOQqE
You can use flex-grow: 0 if you just want the component to take up the space it needs.

Responsive Props in Vue Component

I have a prop called src in a Vue Component that binds to a :style like this:
<template>
<section :class="color" class="hero" :style="{ backgroundImage: src && 'url(' + src + ')' }">
<slot></slot>
</section>
</template>
<script>
export default {
props: ['src', 'color']
}
</script>
What I would like to do is to create a list of responsive props that get used depending on the device or screen size of the site visitor.
For instance, I imagine a list of props like src-sm, src-md, src-lg, etc. The user would enter different image urls for different device sizes and the style attr would use the appropriate url depending on the screen/size.
Is this possible in VueJS. If so, any idea how?
Thanks.
Unfortuently what you are trying to do is not trivial. This is because inline style tags can not accept media queries.
The spec declares:
The value of the style attribute must match the syntax of the contents of a CSS declaration block
Solution 1:
This solution is the simplest, perhaps not entirely what you are looking for.
It works by including img elements, and showing an hiding them via CSS.
<template>
<div>
<img class="image--sm" :src="src.sm" />
<img class="image--md" :src="src.md" />
<img class="image--lg" :src="src.lg" />
</div>
</template>
<script>
export default {
props: {
src: Object
}
}
</script>
<style>
.image--md,
.image--lg {
display: none;
}
#media (min-width: 400px) {
.image--sm {
display: none;
}
.image--md {
display: block;
}
}
#media (min-width: 600px) {
.image--md {
display: none;
}
.image--lg {
display: block;
}
}
</style>
Example: https://jsfiddle.net/h3c5og08/1/
Solution 2:
Image tags may not be the desired effect you are trying to achieve. This solution creates a style tag in the head and injecting the css content to change the background images.
You can not have style tags in Vue template. It will throw an error like:
Templates should only be responsible for mapping the state to the UI. Avoid placing tags with side-effects in your templates, such as , as they will not be parsed.
As the error describes vue is designed the map state the UI. Using style tags in the template is prohibited because you can cause leaks to the outer world.
Although you can not declaratively styles in a template, we can use a bit of JS in the mounted hook of the component to add targetted and dynamic styles.
First we will need to constrain dynamic styles to this element. We can use the internal id of the created component this._uid, attaching to scope the css. (Note this is internal API so can be subject to change)
<template>
<div class="image" :data-style-scope="_uid">
</div>
</template>
The next part is to generate the style in a computed property, to later inject into a style block. You can expand on this computed property, to conditionaly assign properties ect. Note: keep the properties to the dynamic values only.
css () {
const selector = `.image[data-style-scope="${this._uid}"]`
const img = val => `${selector} { background-image: url("${val}"); }`
const sm = img(this.sm)
const md = img(this.md)
const lg = img(this.lg)
return `
${sm}
#media (min-width: 200px) { ${md} }
#media (min-width: 300px) { ${lg} }
`
}
This generated string from the css computed property is what we will now use when creating the style tag at mount. At mount we create a style node and append to the head. Assigning the nodes to the vm for references.
Using the references in the vm we can watch changes to the computed updating the style node.
Remember to clean up before destorying the component, removing the style node.
{
data () {
return {
// Reference data properties
style: null,
styleRef: null
}
},
mounted () {
// Create style node
let style = document.createElement('style')
style.type = "text/css"
style.appendChild(document.createTextNode(''))
// Assign references on vm
this.styleRef = style
this.style = style.childNodes[0]
// Assign css the the style node
this.style.textContent = this.css
// Append to the head
document.head.appendChild(style)
},
beforeDestroy () {
// Remove the style node from the head
this.style.parentElement.removeChild(this.style)
},
computed: {
css () {
// ...
}
},
watch: {
css (value) {
// On css value change update style content
this.style.textContent = this.css
}
}
}
Working Example: https://jsfiddle.net/bLkc51Lz/4/
You could also try the module described here: https://alligator.io/vuejs/vue-responsive-components/ which is called vue-responsive-components
It lets the component change its CSS depending on its own width (not on the entire browser's width)

Resources