Skip to main content

Overview

The Footer component (taskbar) provides the Windows XP taskbar experience with a Start menu, open window buttons, system tray icons, and a clock.

Component Structure

function Footer({
  onMouseDownApp,    // Handler for taskbar window buttons
  apps,              // Array of open applications
  focusedAppId,      // Currently focused app ID
  onMouseDown,       // Generic mousedown handler
  onClickMenuItem,   // Start menu item handler
}) {
  const [time, setTime] = useState(getTime);
  const [menuOn, setMenuOn] = useState(false);
  
  return (
    <Container onMouseDown={_onMouseDown}>
      {/* Start Menu */}
      <div ref={menu} className="footer__start__menu">
        {menuOn && <FooterMenu onClick={_onClickMenuItem} />}
      </div>
      
      {/* Left: Start button + window buttons */}
      <div className="footer__items left">
        <img src={startButton} className="footer__start" onMouseDown={toggleMenu} />
        {apps.map(app => !app.header.noFooterWindow && (
          <FooterWindow key={app.id} {...app} />
        ))}
      </div>

      {/* Right: System tray + clock */}
      <div className="footer__items right">
        <img src={sound} onClick={toggleVolume} />
        <img src={usb} />
        <img src={risk} />
        <Balloon />
        <div className="footer__time">{time}</div>
      </div>
    </Container>
  );
}
Source: src/WinXP/Footer/index.jsx:32-157

Taskbar Layout

Container Styling

const Container = styled.footer`
  height: 30px;
  background: linear-gradient(
    to bottom,
    #1f2f86 0,
    #3165c4 3%,
    #3682e5 6%,
    #4490e6 10%,
    // ... Windows XP blue gradient
  );
  position: absolute;
  bottom: 0;
  right: 0;
  left: 0;
  display: flex;
`;
Source: src/WinXP/Footer/index.jsx:174-199

Left Section (Start + Windows)

.footer__items.left {
  height: 100%;
  flex: 1;
  overflow: hidden;  /* Scroll if too many windows */
}

Right Section (System Tray)

.footer__items.right {
  background: linear-gradient(
    to bottom,
    #0c59b9 1%,
    #139ee9 6%,
    // ... lighter blue gradient
  );
  border-left: 1px solid #1042af;
  box-shadow: inset 1px 0 1px #18bbff;
  padding: 0 10px;
  margin-left: 10px;
  flex-shrink: 0;  /* Fixed width */
}
Source: src/WinXP/Footer/index.jsx:200-227

Start Button

The iconic Windows XP Start button:
<img
  src={startButton}
  alt="start"
  className="footer__start"
  onMouseDown={toggleMenu}
/>

Toggle Logic

function toggleMenu(e) {
  e.stopPropagation();
  onMouseDown();  // Focus desktop
  setMenuOn(on => !on);
}
Source: src/WinXP/Footer/index.jsx:48-52

Styling

.footer__start {
  height: 100%;
  margin-right: 10px;
  position: relative;
  
  &:hover {
    filter: brightness(105%);
  }
  
  &:active {
    pointer-events: none;
    filter: brightness(85%);
  }
}
Source: src/WinXP/Footer/index.jsx:232-243

Start Menu

The Start menu is a complex component with two columns and nested submenus.

Component Structure

function FooterMenu({ className, onClick }) {
  const [hovering, setHovering] = useState('');
  
  return (
    <div className={className}>
      <header>
        <img className="header__img" src={user} alt="avatar" />
        <span className="header__text">Skillz</span>
        <EggCounter />
      </header>
      
      <section className="menu" onMouseOver={onMouseOver}>
        <hr className="orange-hr" />
        <div className="menu__left">
          {/* Pinned programs */}
        </div>
        <div className="menu__right">
          {/* System items */}
        </div>
      </section>
      
      <footer>
        <div onClick={() => onClick('Log Off')}>Log Off</div>
        <div onClick={() => onClick('Turn Off Computer')}>Turn Off Computer</div>
      </footer>
    </div>
  );
}
Source: src/WinXP/Footer/FooterMenu.jsx:94-254
<Item onClick={onClick} text="Internet" icon={ie}>
  <div className="menu__item__subtext">Internet Explorer</div>
</Item>

<Items
  onClick={onClick}
  items={[
    { icon: mine, text: 'Minesweeper' },
    { icon: notepad, text: 'Notepad' },
    { icon: winamp, text: 'Winamp' },
    { icon: paint, text: 'Paint' },
    { icon: mediaPlayer, text: 'Media Player' },
    { icon: messenger, text: 'PictoChat' },
  ]}
/>
Source: src/WinXP/Footer/FooterMenu.jsx:111-128

Egg Counter

The start menu header displays an egg counter:
function EggCounter() {
  const [count, setCount] = useState(() => {
    try {
      const savedData = localStorage.getItem('eggData');
      const parsed = savedData ? JSON.parse(savedData) : [];
      return Array.isArray(parsed) ? parsed.length : 0;
    } catch (e) {
      return 0;
    }
  });

  return (
    <EggCounterContainer>
      <EggCounterIcon src={eggIcon} alt="Egg" />
      <span>x {count}</span>
    </EggCounterContainer>
  );
}
Source: src/WinXP/Footer/FooterMenu.jsx:57-92
The egg counter reads from localStorage and updates in real-time using storage events.
Hovering over items with arrows shows submenus:
<Item
  style={
    hovering === 'All Programs'
      ? { backgroundColor: '#2f71cd', color: '#FFF' }
      : {}
  }
  text="All Programs"
  icon={empty}
>
  {hovering === 'All Programs' && (
    <SubMenu data={AllPrograms} onClick={onClick} />
  )}
</Item>
Source: src/WinXP/Footer/FooterMenu.jsx:132-158
function onClickMenuItem(itemName) {
  switch (itemName) {
    case 'Internet':
      dispatch({ type: ADD_APP, payload: appSettings['Internet Explorer'] });
      break;
    case 'Minesweeper':
      dispatch({ type: ADD_APP, payload: appSettings.Minesweeper });
      break;
    case 'Log Off':
      dispatch({ type: POWER_OFF, payload: POWER_STATE.LOG_OFF });
      break;
    case 'Turn Off Computer':
      dispatch({ type: POWER_OFF, payload: POWER_STATE.TURN_OFF });
      break;
    default:
      dispatch({
        type: ADD_APP,
        payload: {
          ...appSettings.Error,
          injectProps: {
            message: `C:\\\nApplication '${itemName}' not found`,
          },
        },
      });
  }
}
Source: src/WinXP/index.jsx:138-190

Window Buttons

Each open application gets a taskbar button.

Component

function FooterWindow({ id, icon, title, onMouseDown, isFocus }) {
  function _onMouseDown() {
    onMouseDown(id);
  }
  return (
    <div
      onMouseDown={_onMouseDown}
      className={`footer__window ${isFocus ? 'focus' : 'cover'}`}
    >
      <img className="footer__icon" src={icon} alt={title} />
      <div className="footer__text">{title}</div>
    </div>
  );
}
Source: src/WinXP/Footer/index.jsx:159-172

Button Behavior

Clicking a taskbar button has different effects:
function onMouseDownFooterApp(id) {
  const app = state.apps.find(a => a.id === id);
  if (app) {
    if (app.id === focusedAppId && !app.minimized) {
      // Already focused -> minimize
      dispatch({ type: MINIMIZE_APP, payload: id });
    } else {
      // Not focused or minimized -> focus
      dispatch({ type: FOCUS_APP, payload: id });
    }
  }
}
Source: src/WinXP/index.jsx:112-121

Button Styling

.footer__window {
  flex: 1;
  max-width: 150px;
  color: #fff;
  border-radius: 2px;
  margin-top: 2px;
  padding: 0 8px;
  height: 22px;
  font-size: 11px;
  background-color: #3c81f3;
  box-shadow: inset -1px 0px rgba(0, 0, 0, 0.3),
    inset 1px 1px 1px rgba(255, 255, 255, 0.2);
}

/* Focused window */
.footer__window.focus {
  background-color: #1e52b7;
  box-shadow: inset 0 0 1px 1px rgba(0, 0, 0, 0.2),
    inset 1px 0 1px rgba(0, 0, 0, 0.7);
}

/* Hover effect */
.footer__window.cover:hover {
  background-color: #53a3ff;
}
Source: src/WinXP/Footer/index.jsx:250-309

System Tray

Icons

The system tray displays status icons:
<div className="footer__items right">
  <img
    ref={soundIconRef}
    className="footer__icon"
    src={sound}
    alt="Volume"
    onClick={() => setShowVolume(v => !v)}
    style={{ cursor: 'pointer' }}
  />
  <img className="footer__icon" src={usb} alt="" />
  <img className="footer__icon" src={risk} alt="" />
  <Balloon />  {/* Notification balloon */}
  <div className="footer__time">{time}</div>
</div>
Source: src/WinXP/Footer/index.jsx:128-143

Icon Styling

.footer__icon {
  height: 15px;
  width: 15px;
}
Source: src/WinXP/Footer/index.jsx:266-269

Clock

The clock updates every second:
const getTime = () => {
  const date = new Date();
  let hour = date.getHours();
  let hourPostFix = 'AM';
  let min = date.getMinutes();
  
  if (hour >= 12) {
    hour -= 12;
    hourPostFix = 'PM';
  }
  if (hour === 0) {
    hour = 12;
  }
  if (min < 10) {
    min = '0' + min;
  }
  return `${hour}:${min} ${hourPostFix}`;
};

const [time, setTime] = useState(getTime);

useEffect(() => {
  const timer = setInterval(() => {
    const newTime = getTime();
    newTime !== time && setTime(newTime);
  }, 1000);
  return () => clearInterval(timer);
}, [time]);
Source: src/WinXP/Footer/index.jsx:14-67

Clock Styling

.footer__time {
  margin: 0 5px;
  color: #fff;
  font-size: 11px;
  font-weight: lighter;
  text-shadow: none;
}
Source: src/WinXP/Footer/index.jsx:310-316

Volume Control

Clicking the volume icon shows a volume slider:
const [showVolume, setShowVolume] = useState(false);
const { volume, setVolume, isMuted, setIsMuted } = useVolume();

<img
  ref={soundIconRef}
  src={sound}
  onClick={() => setShowVolume(v => !v)}
/>

<div ref={sliderRef}>
  {showVolume && (
    <VolumeSlider
      volume={volume}
      onVolumeChange={setVolume}
      isMuted={isMuted}
      onMuteChange={setIsMuted}
    />
  )}
</div>
Source: src/WinXP/Footer/index.jsx:43-154

Click Outside Handler

useEffect(() => {
  function handleClickOutside(event) {
    if (
      showVolume &&
      sliderRef.current &&
      !sliderRef.current.contains(event.target) &&
      soundIconRef.current &&
      !soundIconRef.current.contains(event.target)
    ) {
      setShowVolume(false);
    }
  }
  document.addEventListener('mousedown', handleClickOutside);
  return () => {
    document.removeEventListener('mousedown', handleClickOutside);
  };
}, [showVolume]);
Source: src/WinXP/Footer/index.jsx:82-99
The volume control integrates with the VolumeContext to persist settings across the application.

Notification Balloon

The system tray includes a notification balloon component:
<div style={{ position: 'relative', width: 0, height: 0 }}>
  <Balloon />
</div>
This provides tooltip-style notifications for system events. The Start menu appears above the Start button:
.footer__start__menu {
  position: absolute;
  left: 0;
  box-shadow: 2px 4px 2px rgba(0, 0, 0, 0.5);
  bottom: 100%;  /* Position above taskbar */
}
Source: src/WinXP/Footer/index.jsx:244-249

Outside Click Detection

The Start menu closes when clicking outside:
useEffect(() => {
  if (!menuOn) return;
  const target = menu.current;
  if (!target) return;
  
  function handleMouseDown(e) {
    if (e.target.closest('.footer__start')) return;  // Ignore Start button
    if (!target.contains(e.target)) {
      setMenuOn(false);
    }
  }
  
  window.addEventListener('mousedown', handleMouseDown);
  return () => window.removeEventListener('mousedown', handleMouseDown);
}, [menuOn]);
Source: src/WinXP/Footer/index.jsx:68-80

Next Steps

Desktop Overview

Return to desktop architecture

Windows

Learn about window management

Icons

Explore desktop icons

Build docs developers (and LLMs) love