Material-UI Table/XGrid - How to set a different color for each cell - material-ui

The styling for cell tables in material-ui is fine when you have a limited known amount of options but I'm struggling when is not known in advance.
To simplify, the idea is setting the background color for each cell based on the table cell values (let's imagine the value of the cell is actually the color).
Using cellRenderers is limited (not really a clean option).
The current solution looks like (doc):
cellClassName: (params: GridCellClassParams) =>
clsx('super-app', {
negative: (params.value as number) < 0,
positive: (params.value as number) > 0,
}),
How could create dynamically add styling or css in material-ui v5/emotion (doc). Something like :
cellSx: (params: GridCellClassParams) =>{
{
backgroundColor: params.value
}
}),

As per your question, I understood that you will receive color names and need to apply those colors on the cells in which the color names are present.
To dynamically create the object present in "clsx" method.
// let us consider that there is a key named color in the params which is received in the colums.
const generateColorsObject = (color) => {
const colorKey = color;
const colorObject = {}
colorObj[colorKey] = color
return colorObj; // it's value will have something like { 'red': 'red' }
}
const columns = [
{
field: 'name',
cellClassName: 'super-app-theme--cell',
},
{
field: 'score',
type: 'number',
width: 140,
cellClassName: (params) =>
clsx('super-app', generateColorsObject(params.color)),
},
];
const useStyles = makeStyles({
root: {
'& .super-app.red': {
backgroundColor: 'red', // you need to configure the background colors to the colorKey
color: '#1a3e72',
fontWeight: '600',
},
'& .super-app.blue': {
backgroundColor: 'blue',
color: '#1a3e72',
fontWeight: '600',
},
'& .super-app.orange': {
backgroundColor: 'orange',
color: '#1a3e72',
fontWeight: '600',
},
},
});

I think it boils down to the problem to create a mui class which applies the styling from the received props.
You can leverage material ui useStyles hook advanced feature to create mui classes which accepts the props, so you can pass over some style details as you want.
const useStyles = makeStyles({
// style rule
foo: props => ({
backgroundColor: props.backgroundColor,
}),
bar: {
// CSS property
color: props => props.color,
},
});
function MyComponent() {
// Simulated props for the purpose of the example
const props = { backgroundColor: 'black', color: 'white' };
// Pass the props as the first argument of useStyles()
const classes = useStyles(props);
return <div className={`${classes.foo} ${classes.bar}`} />
}
You can find the doc from here.

To solve this issue I used the cellClassName and changing the class using a function. Here is my working code:
// Based on the value of the cell the class will be applied.
const applyCellColour = (value: boolean) => (value ? 'notApprovedCell' : 'approvedCell');
// In the columns array in the cellClassName:
const columns: GridColDef[] = [
{
field: 'Approval',
headerName: 'Approval',
headerAlign: 'center',
align: 'center',
cellClassName: params => applyCellColour(params),
},
]
// CSS
.approvedCell {
background-color: 'green';
}
.notApprovedCell {
background-color: 'red';
}

Related

How to use the concept of conditional classes in className when using mui v5 and styled components

I'm aware that mui v5 is now using styled components but wanted to understand how to use the concept of conditional classes className={clsx(isRed && classes.bar)} when using styled components? How would the following example be best written with styled components?
mui v4 example using makeStyles:
import React from "react";
import clsx from "clsx";
import { makeStyles } from "#material-ui/core";
const useStyle = makeStyles({
bar: {
color: "red"
}
});
export const Foo: React.FC<{ isRed?: boolean }> = ({ isRed }) => {
const classes = useStyle();
return <div className={clsx(isRed && classes.bar)}>Hello World</div>;
};
You create a styled component:
import { styled } from "#mui/system";
// this will generate classNames and will assign to the div
const MainContainer = styled("div")({
position: "absolute",
borderRadius: "*px",
....
});
create conditional style objects:
const fullScreen = {
width: "100%",
height: "100vh",
};
const minScreen = {
width: "30%",
height: "40vh",
};
returned jsx
return (
<MainContainer
style={ifConditionTrue ? minScreen : fullScreen}
>
{children}
</MainContainer>
);
I am not sure if you asked for this but you can do these kind of things with conditions.
const useStyle = makeStyles({
departmentAddButton: {
position: "absolute",
maxHeight: 40,
minHeight: 0,
height: 33,
width: 100,
backgroundColor: "#404040", },
departmentAddButtonNoAbsolute: {
maxHeight: 40,
minHeight: 0,
height: 55,
width: 155,
backgroundColor: "#fff",
},
});
const foo = false;
className={clsx({
[classes.userAddButton]: foo === true,
[classes.departmentAddButton]: foo === false,
})}

Correct way to style a section of a material-ui document

I have a header and want to style all of it's buttons differently than my global theme. I have tried using a child theme like:
<ThemeProvider
theme={(outerTheme) =>
_.merge(outerTheme, {
overrides: {
MuiButton: {
label: {
color: "#fff",
},
},
},
})
}
>
However, while I had expected this to override only MuiButton's in the child theme, it overrode them in them globally.
I know I can use makeStyles but, then, as far as I know, I have to reference it in all the child components which want to use the style. I'd like to wrap a higher level component and have all child components pick up the style. How is this done?
You can do this:
import Button from '#material-ui/core/Button';
import { purple } from '#material-ui/core/colors';
import { makeStyles } from '#material-ui/core/styles';
const useStyles = makeStyles((theme) => ({
header: {
"& button": {
marginRight: theme.spacing(1),
color: theme.palette.getContrastText(purple[500]),
backgroundColor: purple[500],
"&:hover": {
backgroundColor: purple[700],
},
},
},
});
function CustomHeader(props) {
const classes = useStyles();
return (
<div className={classes.header}>
<Button>Button 1</Button>
<Button>Button 2</Button>
<Button disabled>Button 3</Button>
</div>
)
};

Why aren't these react-data-grid columns resizable?

I'd like to have a react-data-grid with editable data and resizable columns. Only the last column of my example can be resized.
I have combined 'Basic Editing' and 'Column Resizing' from https://adazzle.github.io/react-data-grid/docs/examples/column-resizing.
import React from 'react';
import ReactDataGrid from 'react-data-grid';
const defaultColumnProperties = {
editable: true,
resizable: true,
width: 120,
};
const columns = [
{ key: 'id', name: 'ID' },
{ key: 'title', name: 'Title' },
{ key: 'complete', name: 'Complete' },
].map(c => ({ ...c, ...defaultColumnProperties }));;
const rows = [
{ id: 0, title: 'Task 1', complete: 20 },
{ id: 1, title: 'Task 2', complete: 40 },
];
class Example extends React.Component {
state = { rows };
onGridRowsUpdated = ({ fromRow, toRow, updated }) => {
this.setState(state => {
const rows = state.rows.slice();
for (let i = fromRow; i <= toRow; i++) {
rows[i] = { ...rows[i], ...updated };
}
return { rows };
});
};
render() {
return (
<ReactDataGrid
columns={columns}
rowGetter={i => this.state.rows[i]}
rowsCount={this.state.rows.length}
minHeight={500}
onColumnResize={(idx, width) =>
console.log(`Column ${idx} has been resized to ${width}`)
}
onGridRowsUpdated={this.onGridRowsUpdated}
enableCellSelect
/>
);
}
}
I expect to be able to grab the vertical separator between column 1 and 2, and drag to widen column 1, but the only grabbable column separator is after the last column, and so the only column I can resize is the last column.
Add this line to index.html
<link rel="stylesheet" media="screen" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.css">
Discovered by diffing another project with working column resizing and this problem project.
While adding Bootstrap CSS does resolve the issue, the simpler solution is to just add the piece of the BS CSS that is needed to regain the box borders:
styles.css
* {
box-sizing: border-box;
}
I just scoped it to the component that is using react-data-grid like so:
styles.scss
#myComponent {
* {
box-sizing: border-box;
}
}

Change onHover colour of TextField Material-UI v1

I m unable to change the onHover color of the TextField by overriding the classname. How can I do that?
I'm using material UI v1: https://github.com/callemall/material-ui/tree/v1-beta
Overriding with classes didn't help.
It worked by overriding MUIclass in createMuiTheme as below.
const theme = createMuiTheme({
overrides: {
MuiInput: {
underline: {
'&:hover:not($disabled):before': {
backgroundColor: 'rgba(0, 188, 212, 0.7)',
},
},
},
},
});
TextField is implemented using the Input component, which exposes a class named underline as part of its CSS API. Here is the the current definition of this class from the Input source:
underline: {
paddingBottom: 2,
'&:before': {
backgroundColor: theme.palette.input.bottomLine,
left: 0,
bottom: 0,
// Doing the other way around crash on IE11 "''" https://github.com/cssinjs/jss/issues/242
content: '""',
height: 1,
position: 'absolute',
right: 0,
transition: theme.transitions.create('backgroundColor', {
duration: theme.transitions.duration.shorter,
easing: theme.transitions.easing.ease,
}),
},
'&:hover:not($disabled):before': {
backgroundColor: theme.palette.text.primary,
height: 2,
},
'&$disabled:before': {
background: 'transparent',
backgroundImage: `linear-gradient(to right, ${theme.palette.input
.bottomLine} 33%, transparent 0%)`,
backgroundPosition: 'left top',
backgroundRepeat: 'repeat-x',
backgroundSize: '5px 1px',
},
},
To override the Input's classes, you need to pass them through the TextField using its InputProps property. Here is an example where I'm changing the color of the underline to green:
// define a class that will be used to modify the underline class
const styleSheet = createStyleSheet(theme => ({
greenUnderline: {
'&:before': {
backgroundColor: '#0f0',
},
},
}));
Override the Input's underline class via the TextField's InputProps:
<TextField
id="uncontrolled"
label="Uncontrolled"
defaultValue="foo"
className={classes.textField}
margin="normal"
InputProps={{ classes: { underline: classes.greenUnderline } }}
/>
This may not be exactly what you're looking to do, but it should get you started.
this worked for me:
export const theme = createMuiTheme({
overrides:{
MuiFilledInput:{
root:{
"&:hover": {
backgroundColor: '#5dc2a6',
}
}
}
});

ExtJS Grid Panel how to change cell background colour conditionally [duplicate]

I have an Extjs Editor Grid panel in which i have to change the css of one column depending upon the value of another column value then how to do it i cannot use renderer function because it works on onload is there any other way i am attaching code in which i have gender column and id column so when gender column select male then background colour of ID should change to Pink colour else not so how to do it.
{
id: 'value',
name: 'value',
header: 'Gender',
dataIndex: 'insured',
width: 100,
editor: new fm.ComboBox({
typeAhead: true,
displayField: 'gender',
mode: 'local',
transform: 'gender',
triggerAction: 'all',
selectOnFocus: true,
forceSelection: true,
stripeRows: true,
lazyRender: true,
listeners: {
}
}
})
},
{
id: 'ID',
name: 'ID',
header: 'ID',
dataIndex: 'ID',
width: 100,
hidden: true,
editor: new fm.TextField({
allowBlank: true,
maxLength: 500
})
}
This will work for simple rendering
CSS:
.custom-column
{
background-color: #ccc;
}
JavaScript:
columns: [{
dataIndex: 'name',
renderer: function (value, meta) {
meta.css = 'custom-column';
return value;
}
}]
Edit:
You can use getRowClass to apply custom CSS classes to rows during rendering.
Override this function to apply custom CSS classes to rows during
rendering. This function should return the CSS class name (or empty
string '' for none) that will be added to the row's wrapping div. To
apply multiple class names, simply return them space-delimited within
the string (e.g. 'my-class another-class').
Javascript:
columns: [{
dataIndex: 'ID',
...
tdCls: 'ID' //add table css class
}],
viewConfig: {
getRowClass: function(record, index) {
var gender = record.get('insured');
if (gender === 0) {
//male
return 'gender-male';
} else if (gender === 1) {
//female
return 'gender-female';
} else {
//unknown
return 'gender-unknown';
}
}
}
Additional CSS:
.gender-male .ID {
background-color: #088da5;
}
.gender-female .ID {
background-color: #f799af;
}
.gender-unknown .ID {
background-color: #BADA55;
}