Update the chess board with grid layout and Context API

Sean
SLTC — Sean Learns To Code
5 min readFeb 11, 2023

In the previous post, where I discussed how to draw a chess board with CSS flexbox, I mentioned that I would love to include the names of the rows and the columns on the UI and ideally I would do that using CSS grid layout. Well, I just did that today! You can check out the latest version of my chess board at https://css-chess-board.netlify.app/.

The updated chessboard with names for rows and columns included

Below is the 2 key changes that I made to the chess board.

Adding names of rows and columns using CSS grid layout

This commit has all the relevant changes.

First, I made the .chess-board div a grid with 10 columns and 10 rows using the CSS code below.

.chess-board {
display: grid;
grid-template:
repeat(10, $cell-size) / repeat(10, $cell-size)
;
}

Why 10 rows and 10 columns you ask? Because I want to structure the grid like this

  | a  b  c  d  e  f  g  h  |
--------------------------------
8 | R N B Q K B N R | 8
7 | P P P P P P P P | 7
6 | | 6
5 | | 5
4 | | 4
3 | | 3
2 | P P P P P P P P | 2
1 | R N B Q K B N R | 1
--------------------------------
| a b c d e f g h |

In the grid above, the top and the bottom rows will be used for the column names while the left most and the right most columns for the row names. This leaves us an 8x8 large area in the center of the grid where the existing chess board will be placed.

To position the board I used the CSS grid-area property below to specify that the existing board starts at row 2 and column 2 of the grid and spans 8 rows and 8 columns.

grid-area: 2 / 2 / span 8 / span 8;

To positions the other components, I updated the JSX code of ChessBoard as follows

export const ChessBoard = () => {
const board = [
['♖', '♘', '♗', '♕', '♔', '♗', '♘', '♖'],
['♙', '♙', '♙', '♙', '♙', '♙', '♙', '♙'],
['', '', '', '', '', '', '', ''],
['', '', '', '', '', '', '', ''],
['', '', '', '', '', '', '', ''],
['', '', '', '', '', '', '', ''],
['♟', '♟', '♟', '♟', '♟', '♟', '♟', '♟'],
['♜', '♞', '♝', '♛','♚', '♝', '♞', '♜'],
]
return (
<div className="chess-board">
<ColNames direction="top" />

<RowNames gridArea="2 / 1 / span 8 / span 1" direction="left" />
<Board board={board} />
<RowNames gridArea="2 / 10 / span 8 / span 1" direction="right" />

<ColNames gridArea="10 / 2 / span 1 / span 8" direction="bottom" />
</div>
);
}

The gridArea prop is used inside the ColNames and the RowNames component to set the grid-area property.

const RowNames = ({gridArea, direction}) => {
const names = [1, 2, 3, 4, 5, 6, 7, 8];
return (
<div className="row-names" style={{ gridArea }}>
{
names.map((name) =>
<div key={`${direction} ${name}`} className={`row-name ${direction}`}>
<strong>{name}</strong>
</div>
)
}
</div>
);
}

const ColNames = ({ gridArea, direction }) => {
const names = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];
return (
<div className="col-names" style={{ gridArea }}>
{
names.map((name) =>
<div key={`${direction} ${name}`} className={`col-name ${direction}`}>
<strong>{name}</strong>
</div>
)
}
</div>
);
}

Note that in a later commit I changed the code to move all the gridArea related parts to the CSS file because I’m not always a fan of handling CSS styling in JavaScript code.

Letting users switch side using React’s Context API

The chess board has white pieces at the bottom and black pieces on top because it was built with an assumption that the player’ side is white. In reality a player doesn’t always play with one color so it would be better to provide users with the ability to switch side.

To implement this feature, I use the Switch component of React Material UI library. When the state of the switch changes, we need to update the UI as follows:

  1. Reverse the order of the column names
  2. Reverse the order of the row names
  3. Reverse the content rows of the chess board
  4. Swap the position of the king and the queen for both side so that the white queen starts on a white cell and the black queen starts on black cell

How should I let the components know the state of the switch has changed? The naive approach is:

  1. Use useState to manage the state of the Switch component
  2. Bubble up the setter of the Switch’s state up the DOM until the lowest common ancestor of the switch and the chess board
  3. Pass the state down to the board as a property in the props
  4. Keep drilling the prop down if needed

While it definitely works, it’s not a fun task to implement and it doesn’t do good to our code base because:

  1. The state of the switch will have to be passed through UI components that don’t really need to know about that data
  2. More work will be required if we want to change the component hierarchy later

This is the kind of situation that the Context API really shines.

First, I created a context.

const PieceColorContext = createContext(undefined);

From the context object, I define its context provider and a custom hook

export const WHITE = "white";
export const BLACK = "black";

export const PieceColorProvider = ({ children }) => {
const [pieceColor, setPieceColor] = useState(WHITE);

const togglePieceColor = () => setPieceColor(pieceColor === WHITE ? BLACK : WHITE);

return (
<PieceColorContext.Provider value={{
pieceColor,
togglePieceColor,
}}
>
{children}
</PieceColorContext.Provider>
);
};

export const usePieceColorContext = () => useContext(PieceColorContext);

The context provider PieceColorProvider needs to wrap around the App component so that the context it provides, which is the object passed to the value prop, is made available to all descendant components of App.

import { PieceColorProvider } from './PieceColorContext';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<PieceColorProvider>
<App />
</PieceColorProvider>
</React.StrictMode>
);

Once this is done, any descendant of App can use the custom hook usePieceColorContext to access the current value of and the setter function of the side switch, i.e. to access the provided context. Below is the updated code of RowNames . All the relevant changes were made in this commit.

export const RowNames = ({gridArea, direction}) => {
const names = [1, 2, 3, 4, 5, 6, 7, 8];
const { pieceColor } = usePieceColorContext();
if (pieceColor === BLACK) {
names.reverse();
}
return (
<div className="row-names" style={{ gridArea }}>
{
names.map((name) =>
<div key={`${direction} ${name}`} className={`row-name ${direction}`}>
<strong>{name}</strong>
</div>
)
}
</div>
);
}
Switching side using the switch component and Context API

Enjoy!

Although I don’t have plan to build a complete and playable chess game, I don’t want this project to stop here. Below are a few ideas that I have for now:

  1. Fetch the daily puzzle from chess.com and show it on the board
  2. Load the script of a chess game and allow people to browse through the game
  3. 🤔

--

--