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
- https://docusaurus.io/docs/creating-pages
- https://developer.mozilla.org/ja/docs/Web/API/Window/localStorage
- https://docusaurus.io/docs/markdown-features/admonitions
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.
-
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. -
Multiple Memo Fields A fixed number (five in this case) of independent memo input fields are provided. Each memo retains its content individually.
-
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.
-
Display of Last Updated Timestamp The date and time when each memo was last edited and saved are displayed.
-
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.
-
State Management (
useState)memoItems: An array of objects containing the memo'stext,lastUpdatedtimestamp, 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.
-
Side Effect Handling (
useEffect)- Loading data from localStorage: Runs only once when the component mounts. It loads saved data from
localStorageand initializes thememoItemsstate. It also includes validation of the data structure. - Saving data to localStorage: Runs whenever the
memoItemsstate changes. It saves the current content ofmemoItemstolocalStorageas 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
memoItemsstate (especiallytextorisManuallyMinimized) changes. It usesuseRefto access the textarea elements and utilizesscrollHeight.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]);
- Loading data from localStorage: Runs only once when the component mounts. It loads saved data from
-
Event Handlers (
useCallback)handleUpdate: Updates thetextandlastUpdatedof the corresponding memo and resetsisManuallyMinimizedtofalsewhen the textarea content changes.handleToggleMinimize: Toggles theisManuallyMinimizedstate 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.
-
UI and Styling
- Uses Docusaurus's
@theme/Layoutto 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
divelements.borderandbackgroundColorare used to create a clickable UI that feels integrated with the textarea.
- Uses Docusaurus's
3. Data Persistence and Security
-
Using
localStorageMemo data is saved tolocalStorageusing a specified key (STORAGE_KEY).JSON.stringifyandJSON.parseare used to convert between objects and strings. -
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
-
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'andoverflowY: 'hidden'in CSS. -
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.
-
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
titleattribute.
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.