ship
SalesForce Simplified

Your Go-To Resource for Streamlined Solutions and Expert Guidance

mountains
Empower Your Business
Dive deep into the world of CRM excellence, where innovation meets practicality, and transform your Salesforce experience with Forceshark's comprehensive resources

Improving Tic-Tac-Toe UX with Animations and Visual Enhancements in LWC

Creating a functional game is one thing. But making it feel good? That’s a whole other level. If you've been following along with our series on building a Tic-Tac-Toe game in Salesforce using Lightning Web Components (LWC), you've probably noticed how each chapter gradually enhances both the logic and the experience. In this article, we’ll crank up the user experience (UX) with a fresh layer of animations and visuals, making the game not just smart but smooth, satisfying, and snappy.

What’s Changed?

This isn’t our first rodeo. You already know the components: BoardComponent, CellComponent, and GameContainer. What we’re introducing today are subtle but powerful improvements across those components that bring animations, transitions, and richer styling.

Let’s break it down by file, showing the full updated version and pointing out the enhancements along the way.

Updated cellComponent – Say Hello to Style

This is where the magic happens. Each individual cell is now styled with CSS classes that animate when hovered over, clicked, or part of a winning combo.

<template>
    <div class={cellClass} onclick={handleClick}>
        <span class={valueClass}>{value}</span>
    </div>
</template>
import { LightningElement, api } from 'lwc';

export default class CellComponent extends LightningElement {
    @api cellId;
    @api value;
    @api isWinning;

    handleClick() {
        if (!this.value) {
            this.dispatchEvent(
                new CustomEvent('click', {
                    bubbles: true,
                    composed: true
                })
            );
        }
    }

    get cellClass() {
        let classes = 'slds-m-around_xxx-small cell';
        if (this.isWinning) classes += ' winning';
        if (!this.value) classes += ' hoverable';
        return classes;
    }

    get valueClass() {
        let classes = 'value';
        if (this.value === 'X') classes += ' x-value';
        if (this.value === 'O') classes += ' o-value';
        if (this.isWinning) classes += ' winning-value';
        return classes;
    }
}
.cell {
    height: 60px;
    border: 1px solid #dddbda;
    text-align: center;
    font-size: 24px;
    line-height: 60px;
    cursor: pointer;
    /* Prevents text selection inside the cell */
    user-select: none;
    /* Smooth transition for hover and other state changes */
    transition: all 0.3s ease;
    background-color: white;
    border-radius: 4px;
}

/* Hover effect for cells to indicate interactivity */
.cell.hoverable:hover {
    background-color: #f3f2f2;
    box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}

/* Style for cells that are part of the winning line */
.cell.winning {
    background-color: #d4f5d4;
    /* Adds a pulsing animation to draw attention */
    animation: pulse 1.5s infinite;
    border: 2px solid #04844b;
}

/* Base style for the value (X or O) inside the cell */
.value {
    display: inline-block;
    /* Smooth scaling effect for animations */
    transition: transform 0.2s ease;
}

/* Sets the color of X to blue */
.x-value {
    color: #0176d3;
}

/* Style for O values */
.o-value {
    color: #ff5d2d;
}

/* Adds a bounce effect to the winning value */
.winning-value {
    animation: bounce 0.5s;
}

/* Keyframes for the pulsing animation of winning cells */
@keyframes pulse {
    /* Initial green background */
    0% { background-color: #d4f5d4; }
    /* Slightly darker green at the midpoint */
    50% { background-color: #a8e6a8; }
    /* Returns to the initial green background */
    100% { background-color: #d4f5d4; }
}

/* Keyframes for the bounce animation of winning values */
@keyframes bounce {
    /* Starts at normal size */
    0% { transform: scale(1); }
    /* Scales up slightly at the midpoint */
    50% { transform: scale(1.2); }
    /* Returns to normal size */
    100% { transform: scale(1); }
}

 What’s New?

  • Hover effect: Unoccupied cells get a subtle glow on hover
  • Winning animation: A pulsing green background and border show off the winning cells
  • Symbol bounce: Xs and Os in the winning line bounce to add emphasis
  • Color coding: Xs are blue, Os are orange - clear, consistent, and friendly

How It All Comes Together

Let’s imagine you’re playing and finally win the game with a diagonal line.

Here’s what the user sees:

  • The winning cells turn green
  • The winning symbols bounce
  • Other cells fade slightly into the background
  • The message updates smoothly to say “Player X wins!

Even a game as simple as Tic-Tac-Toe becomes engaging with that kind of polish.

Wrapping Up

We've taken a functional, logical game and added the kind of finishing touches that make users smile. These enhancements may seem small on paper, but when you play the game, they completely change how it feels.

By using scoped CSS animations, hover feedback, and dynamic styling, we've brought a new level of polish to our LWC Tic-Tac-Toe game. And more importantly, we've shown that user experience isn't just about what you build - it's about how it feels to use.

Continue Reading