Skip to main content

A Record of Implementing an In-Site Browser Memo Feature in Docusaurus

This article outlines the key specifications and technical points for implementing a simple, client-side browser memo feature in a Docusaurus site using React and TypeScript.

Sources

1. Basic Functionality and Purpose

To provide a feature where users can easily create and save text memos within their browser, with the content persisting on their next visit. The emphasis is on simplicity and responsiveness by having all operations run on the client side (using the browser's localStorage) without any server-side processing.

  1. Memo Persistence The entered memo content is automatically saved to the user's browser localStorage. This ensures that the previous content is restored even if the browser is reloaded or closed and reopened.

  2. Multiple Memo Fields A fixed number (five in this case) of independent memo input fields are provided. Each memo retains its content individually.

  3. Automatic Height Adjustment and Manual Minimization Each memo input field automatically adjusts its height based on the amount of text entered. Users can also manually toggle the height to a fixed minimum value.

  4. Display of Last Updated Timestamp The date and time when each memo was last edited and saved are displayed.

  5. Clear All Functionality A function is provided to clear the content of all memos at once.

2. Key Implementation Points

The feature is implemented as a single React component file (browser-memo.tsx) under the src/pages directory.

  1. State Management (useState)

    • memoItems: An array of objects containing the memo's text, lastUpdated timestamp, and manual minimization state (isManuallyMinimized).
      interface MemoItem {
      text: string;
      lastUpdated: number | null;
      isManuallyMinimized: boolean;
      }
      const [memoItems, setMemoItems] = useState<MemoItem[]>(createInitialMemoItems);
    • hoveredIndex: The index of the minimize/auto-adjust toggle area being hovered over by the mouse, used for UI feedback.
  2. Side Effect Handling (useEffect)

    • Loading data from localStorage: Runs only once when the component mounts. It loads saved data from localStorage and initializes the memoItems state. It also includes validation of the data structure.
    • Saving data to localStorage: Runs whenever the memoItems state changes. It saves the current content of memoItems to localStorage as a JSON string. It includes logic to prevent unnecessary saves on initial load.
    • Automatic textarea height adjustment: Dynamically adjusts the height of each textarea when the memoItems state (especially text or isManuallyMinimized) changes. It uses useRef to access the textarea elements and utilizes scrollHeight.
      const adjustTextareaHeight = useCallback((index: number) => {
      const textarea = textareaRefs.current[index];
      if (textarea) {
      const itemIsManuallyMinimized = memoItems[index].isManuallyMinimized;
      if (itemIsManuallyMinimized) {
      textarea.style.height = `${DEFAULT_TEXTAREA_MIN_HEIGHT}px`;
      } else {
      textarea.style.height = 'auto';
      const scrollHeight = textarea.scrollHeight;
      textarea.style.height = `${Math.max(scrollHeight, DEFAULT_TEXTAREA_MIN_HEIGHT)}px`;
      }
      }
      }, [memoItems]);
  3. Event Handlers (useCallback)

    • handleUpdate: Updates the text and lastUpdated of the corresponding memo and resets isManuallyMinimized to false when the textarea content changes.
    • handleToggleMinimize: Toggles the isManuallyMinimized state of the corresponding memo when the minimize/auto-height-adjust toggle area is clicked.
    • handleClearAllMemos: Resets all memo items to their initial state when the "Clear All" button is clicked.
  4. UI and Styling

    • Uses Docusaurus's @theme/Layout to maintain consistency with the overall site design.
    • Major styles are written as inline styles. Utilizes Docusaurus theme variables (var(--ifm-...)) to support light/dark themes.
    • The bottom area of the textarea (containing the minimize/auto-adjust toggle and the last updated timestamp) is implemented with div elements. border and backgroundColor are used to create a clickable UI that feels integrated with the textarea.

3. Data Persistence and Security

  1. Using localStorage Memo data is saved to localStorage using a specified key (STORAGE_KEY). JSON.stringify and JSON.parse are used to convert between objects and strings.

  2. Security Considerations This feature operates entirely on the client side. No data entered is ever sent to an external server. Since the data is stored only within the user's own browser, privacy is protected. However, users should be cautious when using it on shared computers, a point which is noted on the page.

4. UI/UX Points

  1. Automatic Height Adjustment The height of the textarea changes automatically as text is entered, reducing the need for scrolling. This is controlled with JavaScript height manipulation, combined with resize: 'none' and overflowY: 'hidden' in CSS.

  2. Manual Minimization Option Allows users to switch to a fixed minimum height when they want to temporarily make a long memo compact or improve the overview of multiple memos.

  3. Interactive Footer The background color of the bottom area of each memo changes on hover, visually indicating that it is clickable. A tooltip with the action's description is also displayed using the title attribute.

Summary and Thoughts

By combining the standard features of Docusaurus with the flexibility of React, it was relatively easy to add a useful, client-side-only feature. Using localStorage is convenient, but care must be taken with data structure versioning and error handling. I was reminded that fine-tuning the UI/UX (like the height adjustment logic and hover effects) has a significant impact on usability. Future enhancements could include reordering memos, markdown support, or individual memo deletion, but simplicity was prioritized for this implementation.