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
,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.
-
Side Effect Handling (
useEffect
)- Loading data from localStorage: Runs only once when the component mounts. It loads saved data from
localStorage
and initializes thememoItems
state. It also includes validation of the data structure. - Saving data to localStorage: Runs whenever the
memoItems
state changes. It saves the current content ofmemoItems
tolocalStorage
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 (especiallytext
orisManuallyMinimized
) changes. It usesuseRef
to 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 thetext
andlastUpdated
of the corresponding memo and resetsisManuallyMinimized
tofalse
when the textarea content changes.handleToggleMinimize
: Toggles theisManuallyMinimized
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.
-
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
andbackgroundColor
are used to create a clickable UI that feels integrated with the textarea.
- Uses Docusaurus's
3. Data Persistence and Security
-
Using
localStorage
Memo data is saved tolocalStorage
using a specified key (STORAGE_KEY
).JSON.stringify
andJSON.parse
are 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
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.