Focus

Individual cells in the react-bootstrap-data-grid grid can be focused by either clicking on the cell or using keyboard navigation.

Currently, the only feature that focusing on cells enables is copying the text contents of a cell. In the future, as more features such as cell selection and editing are implemented, focusing will be integral to the use of those features.

Style

The grid component attempts to mimic Bootstrap's focus ring helper to visually indicate focused cells.

Color variants are also supported. To customize the color variant of the grid on a per-cell basis, pass functions to the headerCellFocusVariant and bodyCellFocusVariant props to customize header cell and body cells, respectively. See the code sample below for more details on how to use this feature.

Additionally, the grid component obeys customizations to the Bootstrap Sass variables related to focus rings.

Keyboard Navigation

The grid component uses the roving tabindex for the sake of accessibility. This means that when using the Tab and Shift + Tab keys to navigate a web page containing the grid component, only a single cell in the grid can be reached. Pressing Tab or Shift + Tab when focused on a cell in the grid will cause focus to leave the grid.

To focus on different cells within a grid, instead one should use the following keys to navigate between cells. These keys only work when focus is one of the cells inside a grid.

  • Right Arrow: Moves focus one cell to the right. If already at the furthest-right cell, nothing happens.
  • Left Arrow: Moves focus one cell to the left. If already at the furthest-left cell, nothing happens.
  • Down Arrow: Moves focus one cell down. If already at the bottom-most cell, nothing happens.
  • Up Arrow: Moves focus one cell up. If already at the top-most cell, nothing happens.
  • Home: Moves focus to the first cell in the current row.
  • End: Moves focus to the last cell in the current row.
  • Control + Home: Moves focus to the first cell in the first row.
  • Control + End: Moves focus to the last cell in the last row.

For Apple computers, use the Command key instead of the Control key.

Copy Cell Contents

When focused on a cell, the user can copy the text contents of the cell by invoking the clipboard copy function of the browser.

This feature is commonly invoked using the Control + C (Command + C on an Apple computer) keyboard combination.

Example

Live Demo

Unit
Race
Pop
Size
Minerals
Gas
Armor
HP
Shield
Ground Attack
Air Attack
Cooldown
Range
Attack Mod
Sight
Notes
Build Time
Arbiter
Protoss
4
L
100
350
1
200
150
10e
10e
45
5
1
9
S
100.8
Archon
Protoss
4
L
0 (100)
0 (300)
0
10
350
30s
30s
20
2
3
8
(None)
12.6
Carrier
Protoss
6
L
350
250
4
300
150
6
6
(None)
8
1
11
(None)
88
Corsair
Protoss
2
M
150
100
1
100
80
0
5es
8
5
1
9
S
25.2
Dark Archon
Protoss
4
L
0 (250)
0 (200)
1
25
200
0
0
(None)
0
0
10
S
12.6
Dark Templar
Protoss
2
S
125
100
1
80
40
40
0
30
1
3
7
C
31.5
Dragoon
Protoss
2
L
125
50
1
100
80
20e
20e
30
4/6
2
8
(None)
31.5
High Templar
Protoss
2
S
50
150
0
40
40
0
0
(None)
0
0
7
S
31.5
Observer
Protoss
1
S
25
75
0
40
20
0
0
(None)
0
0
9/11
D,C
25.2
Photon Cannon
Protoss
0
L
150
0
0
100
100
20
20
22
7
0
11
D
31.5
Probe
Protoss
1
S
50
0
0
20
20
5
0
22
1
0
8
(None)
12.6
Reaver
Protoss
4
L
200
100
0
100
80
100s/125s
0
60
8
0
10
(None)
44
Scout
Protoss
3
L
275
125
0
150
100
8
28e
30/22
4
1/2
8/10
(None)
50
Shuttle
Protoss
2
L
200
0
1
80
60
0
0
(None)
0
0
8
(None)
37.8
Zealot
Protoss
2
S
100
0
1
100
60
16
0
22
1
2
7
(None)
25.2
Battlecruiser
Terran
6
L
400
300
3
500
0
25
25
30
6
3
11
S
83.79
Dropship
Terran
2
L
100
100
1
150
0
0
0
(None)
0
0
8
(None)
31.5
Firebat
Terran
1
S
50
25
1
50
0
16cs
0
22/11stim
2
2
7
B
15.12
Ghost
Terran
1
S
25
75
0
45
0
10c
10c
22
7
1
9/11
S,B
31.5
Goliath
Terran
2
L
100
50
1
125
0
12
20e
22
5/8
1/4
8
(None)
25.2
Marine
Terran
1
S
50
0
0
40
0
6
6
15/7.5stim
4/5
1
7
B
15.12
Medic
Terran
1
S
50
25
1
60
0
0
0
(None)
0
0
9
S,B
18.9
Missile Turret
Terran
0
L
75
0
0
200
0
0
20e
15
7
0
11
D
18.9
Science Vessel
Terran
2
L
100
225
1
200
0
0
0
(None)
0
0
10
D,S
50
SCV
Terran
1
S
50
0
0
60
0
5
0
15
1
0
7
(None)
12.6
Siege Tank
Terran
2
L
150
100
1
150
0
30e/70es
0
37/75
7/12
3/5
10
(None)
31.5
Spider Mine
Terran
0
S
(None)
(None)
0
20
0
125es
(None)
(None)
0.3
(None)
3
C
(None)
Valkyrie
Terran
3
L
250
125
2
200
0
0
6es
64
6
1
8
(None)
31.5
Vulture
Terran
2
M
75
0
0
80
0
20c
0
30
5
2
8
S
18.9
Wraith
Terran
2
L
150
100
0
120
0
8
20e
30/22
5
1/2
7
S
37.8
Broodling
Zerg
0
S
0
0
0
30
0
4
0
15
1
1
5
B
0
Cocoon
Zerg
2
L
0
0
0
200
0
0
0
(None)
0
0
4
B
0
Defiler
Zerg
2
M
50
150
1
80
0
0
0
(None)
0
0
10
B,S
31.5
Devourer
Zerg
2
L
150 (250)
50 (150)
2
250
0
0
25e
100
6
2
10
B
25(50)
Drone
Zerg
1
S
50
0
0
40
0
5
0
22
1
0
7
B
12.6
Egg
Zerg
0
M
0
0
10
200
0
0
0
(None)
0
0
4
B
0
Guardian
Zerg
2
L
50 (150)
100 (200)
2
150
0
20
0
30
8
2
11
B
25 (50)
Hydralisk
Zerg
1
M
75
25
0
80
0
10e
10e
15
4/5
1
6
B
18
Infested Terran
Zerg
1
S
100
50
0
60
0
500es
0
(None)
1
0
5
B
25
Larva
Zerg
0
S
0
0
10
25
0
0
0
(None)
0
0
4
B
14
Lurker
Zerg
2
M
50 (125)
100 (125)
1
125
0
20s
0
37
6
2
8
B
25 (43)
Mutalisk
Zerg
2
S
100
100
0
120
0
9
9
30
3
1
7
B
25
Overlord
Zerg
0
L
100
0
0
200
0
0
0
(None)
0
0
9/11
B,D
25
Queen
Zerg
2
M
100
100
0
120
0
0
0
(None)
0
0
10
B,S
31.5
Scourge
Zerg
0.5
S
12
38
0
25
0
0
110
(None)
1
0
5
B
19
Spore Colony
Zerg
0
L
+50
0
0
400
0
0
15
15
7
0
10
D
12.6 (25.2)
Sunken Colony
Zerg
0
L
+50
0
2
300
0
40e
0
32
7
0
10
(None)
12.6 (25.2)
Ultralisk
Zerg
4
L
200
200
1/3
400
0
20
0
15
1
3
7
B
38
Zergling
Zerg
0.5
S
25
0
0
35
0
5
0
8/6
1
1
5
B
18

Code

"use client";
 
import { UnitStats } from "./types";
import unitData from "./sc1_unit_stats.json";
import Grid, {
  RowDef,
  ColDef,
  BodyCellVariantFn,
  HeaderCellVariantFn,
} from "@absreim/react-bootstrap-data-grid/grid";
import { FC } from "react";
 
// Data source: Liquipedia
 
const rows: RowDef<UnitStats>[] = (unitData as UnitStats[]).map(
  (unit, index) => ({
    id: index,
    data: {
      ...unit,
    },
  }),
);
 
const cols: ColDef[] = [
  {
    type: "string",
    name: "unit",
    label: "Unit",
    width: 150,
  },
  {
    type: "string",
    name: "race",
    label: "Race",
  },
  {
    type: "number",
    name: "pop",
    label: "Pop",
  },
  {
    type: "string",
    name: "size",
    label: "Size",
  },
  {
    type: "string",
    name: "minerals",
    label: "Minerals",
  },
  {
    type: "string",
    name: "gas",
    label: "Gas",
  },
  {
    type: "string",
    name: "armor",
    label: "Armor",
  },
  {
    type: "number",
    name: "hp",
    label: "HP",
  },
  {
    type: "number",
    name: "shield",
    label: "Shield",
  },
  {
    type: "string",
    name: "groundAttack",
    label: "Ground Attack",
    width: 150,
  },
  {
    type: "string",
    name: "airAttack",
    label: "Air Attack",
  },
  {
    type: "string",
    name: "cooldown",
    label: "Cooldown",
  },
  {
    type: "string",
    name: "range",
    label: "Range",
  },
  {
    type: "string",
    name: "attackMod",
    label: "Attack Mod",
    width: 150,
  },
  {
    type: "string",
    name: "sight",
    label: "Sight",
  },
  {
    type: "string",
    name: "notes",
    label: "Notes",
  },
  {
    type: "string",
    name: "buildTime",
    label: "Build Time",
  },
];
 
const getHeaderCellVariant: HeaderCellVariantFn = () => "primary";
 
const getBodyCellVariant: BodyCellVariantFn = (_, row) => {
  switch (row.contents[1].value) {
    case "Protoss": {
      return "info";
    }
    case "Zerg": {
      return "warning";
    }
    default: {
      return "success";
    }
  }
};
 
const FocusDemoGrid: FC = () => (
  <Grid
    rows={rows}
    cols={cols}
    width="parent"
    headerCellVariant={getHeaderCellVariant}
    headerCellFocusVariant={getHeaderCellVariant}
    bodyCellVariant={getBodyCellVariant}
    bodyCellFocusVariant={getBodyCellVariant}
  />
);
 
export default FocusDemoGrid;