Skip to main content
Notepad is a minimalist text editor that allows users to create, edit, and save plain text files.

Features

  • Text Editing: Full textarea with tab support
  • File Operations: New, Open, Save, Save As
  • Word Wrap: Toggle line wrapping
  • Status Bar: Shows cursor line and column position
  • Time/Date Insertion: Insert current timestamp
  • Tab Support: Proper tab character insertion
  • Cursor Tracking: Real-time line and column display

Component Structure

Location: src/WinXP/apps/Notepad/index.jsx
export default function Notepad({ onClose }) {
  const [docText, setDocText] = useState('');
  const [wordWrap, setWordWrap] = useState(false);
  const [showStatusBar, setShowStatusBar] = useState(false);
  const [cursorPos, setCursorPos] = useState({ col: 1, line: 1 });
  const fileInputRef = useRef(null);
  
  // File operations and text editing
}

Configuration

From apps/index.jsx:
Notepad: {
  name: 'Notepad',
  header: { icon: notepad, title: 'Untitled - Notepad' },
  component: Notepad,
  defaultSize: { width: 660, height: 500 },
  defaultOffset: getCenter(660, 500),
  resizable: true,
  minimized: false,
  maximized: shouldMaximize(660, 500, true),
  multiInstance: true, // Can open multiple instances
}
From dropDownData.js:

File Menu

  • New - Clear text and start new document (functional)
  • Open… - Open text file from disk (functional)
  • Save - Save current document (functional)
  • Save As… - Save with new filename (functional)
  • Separator
  • Page Setup… (disabled)
  • Print… (disabled)
  • Separator
  • Exit - Close Notepad (functional)

Edit Menu

  • Undo… (disabled)
  • Separator
  • Cut, Copy, Paste, Delete (disabled)
  • Separator
  • Find…, Find Next, Replace…, Go To… (disabled)
  • Separator
  • Select All (disabled)
  • Time/Date - Insert current timestamp (functional)

Format Menu

  • Word Wrap - Toggle line wrapping (functional)
  • Font… (disabled)

View Menu

  • Status Bar - Toggle status bar visibility (functional)

Help Menu

  • Help Topics (disabled)
  • About Notepad - Show version info (functional)
function onClickOptionItem(item) {
  switch (item) {
    case 'Exit':
      onClose();
      break;
    case 'New':
      setDocText('');
      break;
    case 'Open...':
      fileInputRef.current.click();
      break;
    case 'Save':
    case 'Save As...':
      downloadFile();
      break;
    case 'Word Wrap':
      setWordWrap(!wordWrap);
      break;
    case 'Status Bar':
      setShowStatusBar(!showStatusBar);
      break;
    case 'Time/Date':
      const date = new Date();
      const timeString = `${date.toLocaleTimeString()} ${date.toLocaleDateString()}`;
      setDocText(prev => prev + timeString);
      break;
    case 'About Notepad':
      alert('Notepad for Windows XP\nVersion 2026 (Web Remake)\n\nCreated by you!');
      break;
    default:
  }
}

File Operations

Opening Files

Uses a hidden file input element:
// Hidden File Input
<input
  type="file"
  ref={fileInputRef}
  style={{ display: 'none' }}
  accept=".txt"
  onChange={onFileChange}
/>

const onFileChange = event => {
  const file = event.target.files[0];
  if (file) {
    const reader = new FileReader();
    reader.onload = e => {
      setDocText(e.target.result);
    };
    reader.readAsText(file);
  }
  // Reset input so you can open the same file twice
  event.target.value = null;
};

Saving Files

Downloads text as a .txt file:
const downloadFile = () => {
  const blob = new Blob([docText], { type: 'text/plain' });
  const url = URL.createObjectURL(blob);
  const link = document.createElement('a');
  link.download = 'Untitled.txt';
  link.href = url;
  link.click();
  URL.revokeObjectURL(url);
};

Text Editing Features

Tab Support

Handles Tab key to insert actual tab character:
function onTextAreaKeyDown(e) {
  updateCursorPos(e);
  
  // Handle tabs in text area
  if (e.which === 9) {
    e.preventDefault();
    e.persist();
    var start = e.target.selectionStart;
    var end = e.target.selectionEnd;
    const newText = `${docText.substring(0, start)}\t${docText.substring(end)}`;
    setDocText(newText);
    
    // Asynchronously update textarea selection to include tab
    requestAnimationFrame(() => {
      e.target.selectionStart = start + 1;
      e.target.selectionEnd = start + 1;
      updateCursorPos({
        target: { value: newText, selectionStart: start + 1 },
      });
    });
  }
}

Cursor Position Tracking

Calculates line and column from textarea selection:
const updateCursorPos = e => {
  const val = e.target.value;
  const sel = e.target.selectionStart;
  
  // Split text up to the selection point to count lines
  const lines = val.substr(0, sel).split('\n');
  const currentLine = lines.length;
  // Length of the last line segment is the column
  const currentCol = lines[lines.length - 1].length + 1;
  
  setCursorPos({ line: currentLine, col: currentCol });
};

Textarea Component

<StyledTextarea
  wordWrap={wordWrap}
  value={docText}
  onChange={e => {
    setDocText(e.target.value);
    updateCursorPos(e);
  }}
  onKeyDown={onTextAreaKeyDown}
  onKeyUp={updateCursorPos}
  onClick={updateCursorPos}
  spellCheck={false}
/>

Styled Textarea

const StyledTextarea = styled.textarea`
  flex: auto;
  outline: none;
  font-family: 'Lucida Console', monospace;
  font-size: 13px;
  line-height: 14px;
  resize: none;
  padding: 2px;
  ${props => (props.wordWrap ? '' : 'white-space: nowrap; overflow-x: scroll;')}
  overflow-y: scroll;
  border: 1px solid #96abff;
  border-top: none;
`;

Status Bar

Displays cursor position when enabled:
{showStatusBar && (
  <StatusBar>
    <div className="left" />
    <div className="right">
      Ln {cursorPos.line}, Col {cursorPos.col}
    </div>
  </StatusBar>
)}

Status Bar Styling

const StatusBar = styled.div`
  height: 20px;
  background: #edede5;
  border-top: 1px solid #d3d3d3;
  display: flex;
  font-family: Tahoma, sans-serif;
  font-size: 11px;
  padding: 2px;
  box-sizing: border-box;
  
  .left {
    flex: 1;
    border-right: 1px solid #d3d3d3;
  }
  
  .right {
    width: 120px;
    padding-left: 5px;
    display: flex;
    align-items: center;
    border-left: 1px solid white;
  }
`;

Word Wrap Toggle

The word wrap feature changes the textarea’s white-space behavior:
/* Word wrap OFF */
white-space: nowrap;
overflow-x: scroll;

/* Word wrap ON */
/* Default textarea wrapping behavior */

Usage Example

import { Notepad } from 'src/WinXP/apps';

function Desktop() {
  return (
    <Window title="Untitled - Notepad">
      <Notepad onClose={handleClose} />
    </Window>
  );
}

Key Features Implementation

Time/Date Insertion

case 'Time/Date':
  const date = new Date();
  const timeString = `${date.toLocaleTimeString()} ${date.toLocaleDateString()}`;
  // Append to end (could be enhanced to insert at cursor)
  setDocText(prev => prev + timeString);
  break;

New Document

case 'New':
  setDocText('');
  break;

Toggle Features

case 'Word Wrap':
  setWordWrap(!wordWrap);
  break;

case 'Status Bar':
  setShowStatusBar(!showStatusBar);
  break;

Build docs developers (and LLMs) love