Styling

There are three primary ways of applying custom styles to the components of React Bootstrap Data Grid:

Bootstrap Variable Overrides
Because React Bootstrap Data Grid makes heavy use of Bootstrap CSS classes and variables, it should also obey customization of Bootstrap via variable overrides. For example, setting a new primary theme color with an SCSS variable will cause buttons of the primary variant in React Bootstrap Data Grid to be the new color as well. Additionally, setting the $table-cell-vertical-align variable can be used to adjust the vertical alignment of table cells from the default of top.
Specific Members of Props in React Bootstrap Data Grid
A small number of options that are set via properties of component props are implemented via CSS classes. Currently, the only properties of this type are the pageSelectorJustifyContent and componentSize properties of the GridPaginationState interface. These properties set the component size and flexbox justify content settings of the Bootstrap pagination component, respectively.
Injection of Custom Classes via the StyleModel Prop
The StyleModel prop contains a fairly extensive of list of properties that correspond to HTML elements in various parts of React Bootstrap Data Grid. These properties either contain arrays of strings that are CSS classes or functions that return an array of such strings.

Type Definitions

StyleModel

A prop of this type is optionally passed to the Grid component to enable injection of custom CSS classes.

Property nameType definitionRequired/OptionalDescription
mainTableStyleModelTableStyleModelOptionalProperties to apply custom CSS classes to elements of the main table of the Grid component
filterInputTableStyleModelFilterInputTableStyleModelOptionalProperties to apply custom CSS classes to elements of the filter inputs table
additionalComponentsStyleModelAdditionalComponentsStyleModelOptionalProperties to apply custom CSS classes for any elements not covered by the other properties in StyleModel

TableStyleModel

Properties of this type are used to inject custom CSS classes into the main table of the Grid component.

When more than one of a certain kind of element exists, a function is used to specify different classes based on the index of the element. Certain parameters are common to many different properties:

origIndex and origRowIndex
Refers to the index of a row as it is passed into the rows prop of the Grid component.
displayIndex
Refers to the index of the row as it is displayed in the table, after sorting, pagination, and filtering are applied.
colIndex
Refers to the index of a column as it corresponds to the cols prop passed into the Grid component.
Property nameType definitionRequired/OptionalDescription
tablestring[]OptionalSpecifies additional CSS classes for the main table element. This element always has the table class to apply Bootstrap styles. In addition, when row selection mode is enabled, the table will have the table-hover class to indicate that the rows are selectable by clicking on them.
tbodystring[]OptionalSpecifies additional CSS classes for the tbody element of the main table.
theadstring[]OptionalSpecifies additional CSS classes for the thead element of the main table.
theadTrstring[]OptionalSpecifies additional CSS classes for the sole tr element of the thead element of the main table.
theadTh(colIndex: number) => string[]OptionalSpecifies additional CSS classes for th elements inside the thead element of the main table. For columns are currently being used for sorting, the Grid will automatically apply the table-active class. In addition, if a column is available as an option for sorting, the Grid will use a CSS class (specific to this project) to set the cursor to be a pointer.
captionstring[]OptionalSpecifies additional CSS classes for the caption element of the main table.
tbodyTr(origIndex: number, displayIndex: number) => string[]OptionalSpecifies additional CSS classes for tr elements inside the tbody element of the main table. The Grid component will automatically apply the table-active class to selected rows.
tbodyTd(origRowIndex: number, displayRowIndex: number, colIndex: number) => string[]OptionalSpecifies additional CSS classes for td elements in side the tbody element of the main table.
editColThstring[]OptionalSpecifies additional CSS classes for the th element of the editing controls column.
editColTd(origIndex: number, displayIndex: number) => string[]OptionalSpecifies additional CSS classes for the td elements of the editing controls column.
selectColThstring[]OptionalSpecifies additional CSS classes for the th element of the selection controls column.
selectColTd(origIndex: number, displayIndex: number) => string[]OptionalSpecifies additional CSS classes for the td elements of the selection controls column.
selectInput(origIndex: number, displayIndex: number) => string[]OptionalSpecifies additional CSS classes for the input elements inside the td elements of the selection controls column.
editStartButton(origIndex: number, displayIndex: number) => string[]OptionalSpecifies the styles for all Edit buttons of the editing controls column. The Grid automatically applies the btn-primary class to these buttons, but if a array of non-zero length is supplied, the btn-primary class will not be applied, allowing for customization of the button variant.
editDeleteButton(origIndex: number, displayIndex: number) => string[]OptionalSpecifies the styles for all Delete buttons of the editing controls column. The Grid automatically applies the btn-secondary class to these buttons, but if a array of non-zero length is supplied, the btn-secondary class will not be applied, allowing for customization of the button variant.
editSaveButton(origIndex: number, displayIndex: number) => string[]OptionalSpecifies the styles for all Save buttons of the editing controls column. The Grid automatically applies the btn-primary class to these buttons, but if a array of non-zero length is supplied, the btn-primary class will not be applied, allowing for customization of the button variant.
editCancelButton(origIndex: number, displayIndex: number) => string[]OptionalSpecifies the styles for all Cancel buttons of the editing controls column. The Grid automatically applies the btn-secondary class to these buttons, but if a array of non-zero length is supplied, the btn-secondary class will not be applied, allowing for customization of the button variant.
rowSelectColThstring[]Optional

Specifies additional classes of the th element that contains the control for selecting and deselecting all rows. The cell only appears if selection for the Grid is enabled by passing a selectModel prop.

By default, the CSS classes btn-primary and rbdg-select-header-cell are applied. The rbdg-select-header-cell class colors the SVG icon of the control based on the Bootstrap button variant. To maximize customizability, the btn-primary class will be omitted if an array of length at least 1 is passed in for this property, allowing one to change the variant of the SVG icon in this cell with a different variant (e.g. btn-secondary.)

There is also a class rbdg-clickable-grid-header-cell that changes the mouse pointer based on whether the cell is clickable.

rowSelectColTd(origIndex: number, displayIndex: number) => string[]OptionalSpecifies additional classes of the td elements in the selection controls column
rowSelectInput(origIndex: number, displayIndex: number) => string[]OptionalSpecifies additional classes of the input elements in the selection controls column

FilterInputTableStyleModel

Properties of this type are used to inject custom CSS classes into the filter options table of the Grid component.

Like the TableStyleModel type, for certain kinds of elements there are more than one of that kind and function parameters are used to specify classes differently for different elements.

index
Zero-based index that refers to the row of filter options as it appears in the UI. The order in which the rows appear is the same as the order corresponding columns in the cols prop to the Grid component, except that only filterable rows are included.
colIndex
Zero-based index that refers to the columns of the filter options table. The columns are fixed regardless of the contents of options passed to the Grid and are as follows:
  1. Enabled - contains checkbox controls to enable or disable filtering on a column
  2. Column - contains the name of the column
  3. Type - contains a string indicating the type of the column (e.g. String or Date)
  4. Operator - contains a selection input to choose operator used to apply filtering
  5. Value - contains inputs to adjust the values to filter on
Property nameType definitionRequired/OptionalDescription
tablestring[]OptionalSpecifies additional CSS classes for the table element of filter options interface. This element always has the table class to apply Bootstrap styles.
tbodystring[]OptionalSpecifies additional CSS classes for the tbody element of the filter options table.
theadstring[]OptionalSpecifies additional CSS classes for the thead element of the filter options table.
theadTrstring[]OptionalSpecifies additional CSS classes for the sole tr element of the thead element of the filter options table.
theadTh(colIndex: number) => string[]OptionalSpecifies additional CSS classes for th elements inside the thead element of the filter options table.
captionstring[]OptionalSpecifies additional CSS classes for the caption element of the filter options table.
tbodyTr(index: number) => string[]OptionalSpecifies additional CSS classes for tr elements inside the tbody element of the filter options table.
tbodyTd(index: number, colIndex: number) => string[]OptionalSpecifies additional CSS classes for td elements in side the tbody element of the filter options table.
enablementInput(rowIndex: number) => string[]OptionalSpecifies additional CSS classes for input checkbox elements that enable and disable filtering based on certain fields.
schemeSelectionInput(rowIndex: number) => string[]OptionalSpecifies additional CSS classes for the select elements that are used to adjust the operators used for filtering for a field.
searchStringInput(rowIndex: number) => string[]OptionalSpecifies additional CSS classes for the input elements used to specify string values on which to filter. This property only applies if the row is associated with a column of type string. It is up to the developer to confirm that fact.
numberInput(rowIndex: number) => string[]OptionalSpecifies additional CSS classes for the input elements used to specify the number values on which to filter. This property only applies if the row is associated with a column of type number. It is up to the developer to confirm that fact.
startDateInput(rowIndex: number) => string[]OptionalSpecifies additional CSS classes for the input elements used to specify the starting dates or datetimes on which to filter. This property only applies if the row is associated with a column of type date or datetime. It is up to the developer to confirm that fact.
endDateInput(rowIndex: number) => string[]OptionalSpecifies additional CSS classes for the input elements used to specify the ending dates or datetimes on which to filter. This property only applies if the row is associated with a column of type date or datetime. It is up to the developer to confirm that fact.
submitButtonstring[]OptionalSpecifies additional CSS classes for the submit button used to save changes to the filter criteria. The btn-secondary class is applied automatically, but will not be applied if an array of length at least 1 is passed for property.

AdditionalComponentsStyleModel

Property nameType definitionRequired/OptionalDescription
topLevelDivstring[]Optional

CSS classes for the top level div element that contains other divs, the following order:

  • A div that contains the button to toggle the visibility of the filter options table followed by the filter options table itself
  • A div that contains he main table for displaying data followed by the pagination component (if pagination is enabled)
filterInputsDivstring[]OptionalCSS classes for the div that contains toggle button for the filter options table followed by the filter options table itself
tableAndPaginationDivstring[]OptionalCSS classes for the div that contains main table followed by the pagination component if pagination is enabled
filterUiToggleButtonstring[]Optional

CSS classes for the button that toggles the visibility of the filter options table. Only appears if filtering is enabled (by supplying the filterModel prop) on the Grid component.

The variant of this button is set to primary by default via the btn-primary class. That class will not be applied if a non-empty is passed via this property.

Examples

Colors and Alignment Example

Code


"use client";

import Grid, { ColDef, RowDef, StyleModel, TableStyleModel } from "@/grid";
import { FC, useMemo } from "react";

const cols: ColDef[] = [
  {
    type: "string",
    name: "variant",
    label: "Variant",
  },
  {
    type: "string",
    name: "color",
    label: "Color",
  },
  {
    type: "string",
    name: "alignment",
    label: "Alignment",
  },
  {
    type: "string",
    name: "placeholderText",
    label: "Placeholder Text",
  },
];

type PartialRow = Record<"variant" | "alignment", string>;
const partialRows: PartialRow[] = [
  {
    variant: "primary",
    alignment: "baseline",
  },
  {
    variant: "secondary",
    alignment: "top",
  },
  {
    variant: "success",
    alignment: "middle",
  },
  {
    variant: "danger",
    alignment: "bottom",
  },
  {
    variant: "warning",
    alignment: "text-top",
  },
  {
    variant: "info",
    alignment: "text-bottom",
  },
  {
    variant: "light",
    alignment: "baseline",
  },
  {
    variant: "dark",
    alignment: "top",
  },
];

const placeholderText =
  "This is placeholder text intended to take up space in order to demonstrate " +
  "the effects of vertical alignment. If cell being vertically aligned is the " +
  "tallest column for a row, then vertical alignment will have no effect. " +
  "There should be enough text here to demonstrate the effect even at the " +
  "largest breakpoint.";

const getComputedTableColors: (variants: string[]) => string[] = (variants) => {
  const table: HTMLTableElement = document.createElement("table");
  table.className = "table";
  table.style.position = "absolute";
  table.style.visibility = "hidden";

  const tbody = table.createTBody();

  variants.forEach((variant) => {
    const tr: HTMLTableRowElement = document.createElement("tr");
    tr.className = `table-${variant}`;

    const td: HTMLTableCellElement = document.createElement("td");

    tr.appendChild(td);
    tbody.appendChild(tr);
  });

  document.body.appendChild(table);

  const colors = Array.from(tbody.children).map((tr) => {
    const td = tr.firstElementChild!;
    return getComputedStyle(td).backgroundColor;
  });

  table.remove();
  return colors;
};

const getRows: (partialRows: PartialRow[], colors: string[]) => RowDef[] = (
  partialRows,
  colors,
) =>
  partialRows.map((_, index) => ({
    variant: partialRows[index].variant,
    color: colors[index],
    alignment: partialRows[index].alignment,
    placeholderText: placeholderText,
  }));

const tableStyleModel: TableStyleModel = {
  caption: ["caption-top"],
  table: ["table-bordered", "border-primary"],
  tbodyTr: (origIndex) => [`table-${partialRows[origIndex].variant}`],
  tbodyTd: (origRowIndex, _, colIndex) =>
    colIndex === 2 ? [`align-${partialRows[origRowIndex].alignment}`] : [],
};

const styleModel: StyleModel = {
  mainTableStyleModel: tableStyleModel,
};

const caption: string =
  "Table demonstrating various ways of customizing " +
  "styling with classes built into Bootstrap";

const SampleStyledGrid: FC = () => {
  const rows = useMemo(() => {
    const variants = partialRows.map(({ variant }) => variant);
    const colors = getComputedTableColors(variants);
    return getRows(partialRows, colors);
  }, []);

  return (
    <Grid rows={rows} cols={cols} styleModel={styleModel} caption={caption} />
  );
};

export default SampleStyledGrid;

Live Demo

Inputs and Display Order Example

Code


import Grid, {
  ColDef,
  EditableTableFilterState,
  EditModel,
  FilterModel,
  RowDef,
  StyleModel,
  UpdateCallbackGenerator,
} from "@/grid";
import { FC, MouseEventHandler, useCallback, useMemo, useState } from "react";

const cols: ColDef[] = [
  {
    type: "string",
    name: "name",
    label: "Name",
  },
  {
    type: "number",
    name: "timesAttended",
    label: "Times Attended",
  },
  {
    type: "date",
    name: "recruitmentDate",
    label: "Recruitment Date",
  },
];

const initRows: RowDef[] = [
  {
    name: "Commander Shepard",
    timesAttended: 100,
    recruitmentDate: new Date("2183-01-01"),
  },
  {
    name: "Kaidan Alenko",
    timesAttended: 25,
    recruitmentDate: new Date("2183-01-02"),
  },
  {
    name: "Ashley Williams",
    timesAttended: 20,
    recruitmentDate: new Date("2183-01-10"),
  },
  {
    name: "Garrus Vakarian",
    timesAttended: 15,
    recruitmentDate: new Date("2183-02-01"),
  },
  {
    name: "Tali'Zorah nar Rayya",
    timesAttended: 12,
    recruitmentDate: new Date("2183-03-15"),
  },
  {
    name: "Urdnot Wrex",
    timesAttended: 10,
    recruitmentDate: new Date("2183-03-20"),
  },
  {
    name: "Liara T'soni",
    timesAttended: 8,
    recruitmentDate: new Date("2183-06-21"),
  },
];

const caption = "Normandy SR-1 Insiders";

const styleModel: StyleModel = {
  mainTableStyleModel: {
    table: ["table-striped"],
    tbodyTdInput: () => ["form-control-sm"],
    editDeleteButton: () => ["btn-danger"],
    editSaveButton: () => ["btn-success"],
    editCancelButton: () => ["btn-warning"],
  },
  additionalComponentsStyleModel: {
    topLevelDiv: ["vstack flex-column-reverse border"],
    filterInputsDiv: ["vstack flex-column-reverse align-items-start border m-2 p-2 gap-2"],
    tableAndPaginationDiv: ["vstack flex-column-reverse border m-2 p-2"],
    filterUiToggleButton: ["btn-info"],
  },
  filterInputTableStyleModel: {
    table: ["table-striped-columns"],
    startDateInput: () => ["form-control-sm"],
    endDateInput: () => ["form-control-sm"],
    submitButton: ["btn-success"],
  },
};

const SampleStyledInputsGrid: FC = () => {
  const [rows, setRows] = useState<RowDef[]>(initRows);
  const [tableFilterState, setTableFilterState] =
    useState<EditableTableFilterState>({
      name: {
        type: "string",
        scheme: "contains",
        searchString: "",
        enabled: false,
      },
      timesAttended: {
        type: "number",
        scheme: "greaterOrEqual",
        numValue: null,
        enabled: false,
      },
      recruitmentDate: {
        type: "date",
        scheme: "between",
        startDate: null,
        endDate: null,
        enabled: false,
      },
    });

  const filterModel: FilterModel = useMemo(
    () => ({
      tableFilterState,
      setTableFilterState,
    }),
    [tableFilterState],
  );

  const getUpdateCallback: UpdateCallbackGenerator = useCallback(
    (origIndex) => (rowDef) => {
      setRows((rows) => {
        const newRows = rows.slice();
        newRows[origIndex] = rowDef;
        return newRows;
      });
    },
    [],
  );
  const getDeleteCallback: (origIndex: number) => () => void = useCallback(
    (origIndex) => () => {
      setRows((rows) => rows.toSpliced(origIndex, 1));
    },
    [],
  );

  const editModel: EditModel = { getUpdateCallback, getDeleteCallback };
  const handleReset: MouseEventHandler<HTMLButtonElement> = () => {
    setRows(initRows);
  }

  return (
    <div className="vstack gap-2 align-items-start border p-2">
      <Grid
        rows={rows}
        cols={cols}
        caption={caption}
        filterModel={filterModel}
        editModel={editModel}
        styleModel={styleModel}
      />
      <button className="btn btn-secondary btn-sm" onClick={handleReset}>
        Reset Rows
      </button>
    </div>
  );
};

export default SampleStyledInputsGrid;

Live Demo

Normandy SR-1 Insiders
NameTimes AttendedRecruitment DateEdit Controls
Commander Shepard100Wed Jan 01 2183
Kaidan Alenko25Thu Jan 02 2183
Ashley Williams20Fri Jan 10 2183
Garrus Vakarian15Sat Feb 01 2183
Tali'Zorah nar Rayya12Sat Mar 15 2183
Urdnot Wrex10Thu Mar 20 2183
Liara T'soni8Sat Jun 21 2183