Styling Smart.Grid with React

Styling React Smart.Grid with CSS Styles

What is Smart.Grid?

When working with lots of data the basic tables aren't the best choice. In such a situation a Grid Component comes in help. Smart.Grid will help you easily manage the data. The Component allows you to sort, filter, edit and group the data. Smart.Grid works not only with React but with Angular, Vue, Blazor and vanilla JavaScript.

You can read everything about Smart.Grid here

Different approaches to styling Smart.Grid with React

The goal of this topic is to show you different ways of styling the Grid React Component.

There are three main approaches and each of them is good at a specific situation:

  • Using inline styles
  • Applying CSS Classes to the Rows/Cells
  • Using Row/Cells CSS rules

For our quick tutorial we will use a Smart.Grid in which we will have a list of people with first name, last name, age and gender.

Setup React Environment

The easiest way is via create-react-app. Open a terminal and type:

npx create-react-app smart-app
cd smart-app

  1. open src/App.js and everything inside the div with className App
    <div className="App"> </div>
  2. remove import logo from './logo.svg';
  3. remove everything from App.css
  4. remove src/logo.svg

Setup Smart UI

Smart UI for React is distributed as smart-webcomponents-react NPM package

  1. Open the terminal and install the package:
    npm install smart-webcomponents-react
  2. Import the default styles in the App.js
    import 'smart-webcomponents-react/source/styles/smart.default.css';
    import './App.css';
    
    function App() {
      return (
        <div className="App"></div>
      );
    }
    
    export default App;
  3. import the Grid Component
    import { Grid } from 'smart-webcomponents-react/grid';

Initialize Grid

The first thing is to initialize a grid with four columns for the first name, last name, age and gender.

Our Grid supports sorting, filtering and paging so we will enable them also.

For the data we will use the following method (which will stay outside the component) to generate our data:

const generateGridData = (rows) => {

  const data = [];

  const firstNames = ['Peter', 'Alexander', 'George', 'Steve', 'Zlat', 'Philip', 'Michael', 'Oliver', 'Kassandra', 'Maria', 'Iglika'];
  const lastNames = ['Madison', 'Marley', 'Bolden', 'Raven', 'Steve', 'Plain', 'Michael', 'Hansley', 'Ashley', 'Monroe', 'West'];

  for (let i = 0; i < rows; i++) {

    const row = {
      firstName: firstNames[Math.floor(Math.random() * (firstNames.length - 0) + 0)],
      lastName: lastNames[Math.floor(Math.random() * (lastNames.length - 0) + 0)],
      age: Math.floor(Math.random() * (110 - 10) + 10),
      gender: Math.random() > 0.5 ? 'male' : 'female'
    }

    data.push(row);

  }

  return data;
}

Now we will define our grid's settings. The number '30' in the generateGridData method is the desired number of rows

const gridSettings = {
  dataSource: new window.Smart.DataAdapter({
    dataSource: generateGridData(30),
    dataFields: [
      'firstName: string',
      'lastName: string',
      'age: number',
      'gender: string'
    ]
  }),
  selection: {
    enabled: true,
    action: 'click',
    mode: 'one'
  },
  sorting: {
    enabled: true,
    sortMode: 'one'
  },
  filtering: {
    enabled: true
  },
  paging: {
    enabled: true,
    pageSize: 15
  },
  pager: {
    visible: true,
    pageSizeSelector: {
      visible: true,
      dataSource: [15, 30, 50]
    }
  },
  columns: [
    {
      label: 'First Name',
      dataField: 'firstName'
    },
    {
      label: 'Last Name',
      dataField: 'lastName'
    }, {
      label: 'Age',
      dataField: 'age'
    },
    {
      label: 'Gender',
      dataField: 'gender'
    }
  ]
}

Since we have a settings for the grid its time to add our component to the template

<div className="App">
  <Grid id="grid" {...gridSettings} />
</div>

Styling Rows and Cells with inline styles

The first method is adding a style directly to a row or cell. It is good when you want to set a few properties. Overall it is better to use CSS classes because a better separation is achieved and styling with classes makes the code cleaner.

We will see how to style cells using setCellStyle, formatFunction and styling rows with setRowStyle

  1. Adding style with the setCellStyle function

    This method supports the following properties: background, color, fontSize, fontFamily, fontWeight and fontStyle

    So we need to add a style to a cell after the grid is initialized.

    Smart.Grid accepts a callback which is executed after the grid has been initialized and the Grid's Virtual DOM is created: onAfterInit()

    It is a method in the grid settings object and in it the this is bound to the grid and we can invoke the method of the grid setCellStyle which accepts: (rowId: string | number, dataField: string, rowStyle) where rowStyle is an object with the above-mentioned properties that are available for changing.

    If we want to change the background color of the first name cell of the first row, we will do the following:

    onAfterInit() {
    
      this.setCellStyle(0, 'firstName', {
        background: 'coral',
        color: 'black'
      });
      
    }

    The result of this is the following:

  2. Adding style to a cell with formatFunction

    You can style cells dynamically by setting up the column's formatFunction

    The formatFunction is being set in the column's definition as a method.

    the function accepts 'settings' from which you can access the cell, row, column, formattedValue, oldValue, template and value

    Here is an example of changing the cell's background of the people whose age is less or greater than 18

    {
      label: 'Age',
      dataField: 'age',
      formatFunction(settings) {
        
        if (settings.value < 18) {
    
          settings.cell.background = 'crimson';
    
        } else {
    
          settings.cell.background = 'lightgreen';
    
        }
    
      }
    }

    The result is:

  3. Adding style to a row with the setRowStyle function

    You can styles to a row with the Grid's method setRowStyle

    The method accepts two arguments: rowId and a style object.

    The style object may have one or all of the following properties: 'background', 'color', 'fontSize', 'fontFamily', 'textDecoration', 'fontStyle', 'fontWeight'.

    NOTE THAT onAfterInit() function is a property of the Grid and in our case it is in the grid settings object!

    An example of using it again after the grid's initialization:

    onAfterInit() {
    
      for (let i = 0; i < this.rows.length; i++) {
    
        if (i % 3 === 0) {
    
          this.setRowStyle(i, {
            background: 'PeachPuff',
            color: 'black',
            fontFamily: 'Roboto'
          });
          
        }
      }
    
    }

    The result is:

Styling Rows and Cells by setting CSS class

With CSS classes we can reuse styles, have more clear code and is generally a more maintainable way to style our application than with inline styles.

We will create a class which will transorm the text to uppercase and a class for the background.

Go to App.css and add the following class

.to-upper {
  text-transform: uppercase;
}

.fancy-bg {
  background: blanchedalmond;
}

Now the ways of adding classes are cellsClassName, highlightCell, highlightRow and onRowClass

  1. Adding a class with the cellsClassName property

    Adding cellsClassName in the column's definition will add the class to the cells in that column

    Multiple classes are passed with a space between them.

    Adding our styles to a column:

    {
      label: 'First Name',
      dataField: 'firstName',
      cellsClassName: 'to-upper fancy-bg'
    }

    The added classes to the cells result in:

  2. Adding class via the 'highlightCell' and 'highlightRow' method

    'highlightCell' and 'highlightRow' allow us to add a single class to a single cell. If you call the method and pass the same cell or row it will remove the previously added class.

    We will use it again in the onAfterInit function:

    onAfterInit() {
    
      for (let i = 0; i < this.rows.length; i++) {
    
        if (i % 3 === 0) {
    
          this.highlightCell(i, 'firstName', 'fancy-bg');
          this.highlightRow(i, 'to-upper');
    
        }
      }
    
    }

    The result:

  3. Adding class to a row with the 'onRowClass'

    'onRowClass' is being executed for each row and accepts (index, data, row). The method should return a string represеnting a class ('my-row-class') or multiple classes separated by a space ('my-row-class my-row-class-2')

    It is a Grid's property and in our case it will be a method in the grid settings

    Our example will highlight all women

    onRowClass(index, data, row) {
    
      if(data.gender === 'female') {
    
        return 'to-upper fancy-bg';
    
      }
    
    }

    The result:

Styling Rows and Cells with CSS Rules

You can add CSS classes under certain conditions.

The settings object for the rows' rules contains the following properties: index, data, row and for the cells contains: index, value, dataField, row

  1. Using CSS Rules with Cells is the same as the CellsClassName

    We will apply our 'fancy-bg' and 'to-upper' on the gender's cells

    {
      label: 'Gender',
      dataField: 'gender',
      cellsCSSRules: {
        'to-upper': settings => settings.value === 'female',
        'fancy-bg': settings => settings.value === 'female',
      }
    }

    Here is the result:

  2. The usage is the same, except rowCSSRules is a property of the Grid

    We will apply our 'fancy-bg' and 'to-upper' on the whole row

    rowCSSRules: {
      'to-upper': settings => settings.data.gender === 'female',
      'fancy-bg': settings => settings.data.gender === 'female',
    }

    Here is the result: