Skip to main content
The MenuItem component represents a single country in the menu list. It renders a checkbox that allows users to mark countries as visited or unvisited.

Overview

The MenuItem component:
  • Displays a country checkbox with label
  • Handles selection/deselection of countries
  • Updates global state through Jotai atoms
  • Provides hover effects for better UX
  • Uses memo for performance optimization

Props

interface Props {
  country: Country;
}
country
Country
required
Country object containing name, ISO code, and selection state

Country Type

The Country interface is defined as:
export interface Country {
  name: string;
  iso3166: string;
  region: string;
  bounds?: [number, number, number, number];
  selected?: boolean;
}
name
string
required
Display name of the country
iso3166
string
required
ISO 3166-1 alpha-2 country code (e.g., “US”, “GB”, “JP”)
region
string
required
Geographic region the country belongs to
bounds
[number, number, number, number]
Bounding box coordinates for map focus [west, south, east, north]
selected
boolean
Whether the country is currently marked as visited

Component Signature

export const MenuItem: FC<Props> = memo(({ country }) => {
  // Component implementation
});

Features

State Management

The component uses Jotai write-only atoms to update the global state:
const addCountry = useSetAtom(addCountryAtom);
const removeCountry = useSetAtom(removeCountryAtom);

const toggleCountry = useCallback(() => {
  if (country.selected) {
    removeCountry(country.iso3166);
  } else {
    addCountry(country.iso3166);
  }
}, [country, addCountry, removeCountry]);

Checkbox Behavior

The checkbox reflects the country’s selection state and triggers updates on change:
<input
  id={country.iso3166}
  type="checkbox"
  checked={country.selected}
  onChange={toggleCountry}
/>

Usage Example

import { MenuItem } from './components/menu-item';
import type { Country } from './models/country';

const country: Country = {
  name: 'United States',
  iso3166: 'US',
  region: 'Americas',
  bounds: [-125.0, 24.0, -66.0, 49.0],
  selected: false,
};

function CountryList() {
  return (
    <ul>
      <MenuItem country={country} />
    </ul>
  );
}

Rendering

The component renders as a list item containing a label with checkbox and text:
<li className="hover:bg-zinc-50 dark:hover:bg-zinc-800">
  <label className="flex items-center px-4 py-1">
    <input
      id={country.iso3166}
      className="my-0 me-2 size-4 rounded border-zinc-400"
      type="checkbox"
      checked={country.selected}
      onChange={toggleCountry}
    />
    <span>{country.name}</span>
  </label>
</li>

Styling

The component uses Tailwind CSS classes for styling:
  • Hover effect: Background changes on hover (hover:bg-zinc-50)
  • Dark mode: Supports dark theme with dark: variants
  • Checkbox: Custom styled with primary color when checked
  • Focus ring: Visible focus indicator for accessibility

Checkbox Styles

size-4           /* 16x16px checkbox */
rounded          /* Rounded corners */
border-zinc-400  /* Border color */
checked:bg-primary  /* Primary color when checked */
focus:ring-2     /* Focus ring for accessibility */

Accessibility

  • Uses semantic <label> element wrapping the checkbox
  • Checkbox id matches the label’s implicit association
  • Keyboard accessible (Space/Enter to toggle)
  • Focus visible with ring indicator
  • Screen reader friendly structure

Performance

The component is wrapped with memo() to prevent unnecessary re-renders:
export const MenuItem: FC<Props> = memo(({ country }) => {
  // Only re-renders when country prop changes
});
The toggleCountry callback is memoized with useCallback to maintain referential equality:
const toggleCountry = useCallback(() => {
  // Callback logic
}, [country, addCountry, removeCountry]);

State Updates

When a checkbox is toggled, it dispatches actions to Jotai atoms:
  • Add: addCountryAtom adds the country’s ISO code to the selection
  • Remove: removeCountryAtom removes the country’s ISO code from the selection
These updates trigger:
  1. Re-render of the MenuItem with updated selected state
  2. Update of the Globe component to highlight/unhighlight the country
  3. Recalculation of Progress indicators in parent regions

Dependencies

  • jotai - State management
  • react - Core React functionality
  • Country type from models/country

Source Code

Location: src/components/menu-item.tsx

Build docs developers (and LLMs) love