This project represents my solution for the Karomia Frontend Challenge, focusing on implementing an in-line tagging system within a rich text editor. The goal is to allow users to easily see which parts of the text link to specific data points by tagging arbitrary ranges and highlighting text based on selected tags.
This solution utilizes React for the frontend framework (overlayed with a Karomia UI sauce), Tiptap for the rich text editor, Jotai for state management, and React Aria Components for accessible UI elements.
This section details each implemented feature with explanations and visual aids.
To ensure that the user's tags and editor content are preserved across browser sessions, this application utilizes localStorage in conjunction with Jotai's atomWithStorage.
-
Tags: The list of created tags (including their name, color, ID, active state) is automatically saved to
localStorageunder the keykaromia_tagswhenever a tag is added or deleted. On subsequent visits, the application loads these tags fromlocalStorageinto the global state. -
Editor Content: The entire content of the rich text editor, including any applied tags as marks, is also automatically saved to
localStorageunder the keykaromia_editor_contentwhenever the content changes.
When the application starts, it first checks if there is any saved editor content in localStorage. If content is found, it is loaded directly into the editor. If no saved content exists, the application proceeds to fetch the initial Markdown content from the mocked API (using React Query hook). This Markdown is then converted to HTML using the marked library and rendered within the Tiptap editor.
On smaller viewports, the TagList is initially hidden behind a hamburger menu in the top right of the navigation bar. Clicking the hamburger icon slides the TagList into view from the right.
Also, the editor toolbar is moved to the bottom on the smallest viewports.
The Tiptap editor supports basic text formatting options such as bold, italic, headings, lists, and text alignment, accessible via a custom toolbar.
When the user selects a portion of text in the editor, an icon button (to manage tags for the currently selected text) appears via a BubbleMenu.
Clicking the icon button reveals a form within the BubbleMenu where users can:
- Specify a tag name/label.
- Pick a tag color using a color picker.
Users can then click an "Add" button to create the tag and assign it to the selected text.
The BubbleMenu also displays a list of existing tags (from the Jotai store) using a ListBox from React Aria. Users can click on a tag in the list to apply it to the currently selected text.
This list also displays the active tags for the currently selected text. So, when clicking an active tag, it will remove this tag from the selection as well.
Tagged segments of text are visually distinguished in the editor by a background color and a bottom border, both derived from the tag's color. Overlapping tags are also visually represented by using stacked backgrounds with opacity.
A TagList component is displayed next to the editor, showing all created tags (sorted alphabetically) with their name, color (as a swatch), and the number of times they are used in the editor. It also displays the number of tags in the title.
Each tag in the TagList has a "Highlight" button. Clicking this button highlights all occurrences of that tag in the editor. Clicking again toggles the highlighting off.
Each tag in the TagList also has a "Delete" button. Clicking it removes the tag from the store and all its associated marks from the editor content.
A "Clear" icon button is available in the TagList to clear all tags. Clicking it removes all tags from the store and all its associated marks from the editor content.
-
Frontend:
React: for building the user interface.React Aria Components: for accessible and unstyled UI components.CSS modules: for scoped styling of components with SASS.React Hook Form: for form management and validation.Zod: for schema validation.Axios+React Query: for making HTTP requests to the backend.react-error-boundary: for handling uncaught errors during rendering.svgr: transforming SVG into React components for ease of use.
-
Backend:
Node.js: for the server-side runtime environment.Express.js: for building the REST API.Multer: for handling file uploads.Pinecone: for the vector database.LangChain: for interacting with LLMs (OpenAI / Hugging Face) and generating embeddings.dotenv: for managing environment variables.cors: For handling Cross-Origin Resource Sharing.uuid: For generating unique identifiers.
βββ public # Contains static assets served by Vite.
βββ src
βΒ Β βββ @tiptap # Contains internal UI components, hooks, styles and logic specifically tailored for the Tiptap editor.
βΒ Β βββ assets
βΒ Β βΒ Β βββ icons # SVG icons used throughout the application.
βΒ Β βΒ Β βββ images # Raster images used in the application (e.g., logo, empty state).
βΒ Β βββ components
βΒ Β βΒ Β βββ app # The main application component.
βΒ Β βΒ Β βββ bubble-menu # Components related to the Tiptap bubble menu for tagging.
βΒ Β βΒ Β βΒ Β βββ bubble-menu-form # Component for the tag creation form within the bubble menu.
βΒ Β βΒ Β βΒ Β βββ bubble-menu-tag-list # Component for the list of existing tags within the bubble menu.
βΒ Β βΒ Β βββ nav-bar # The application's navigation bar component.
βΒ Β βΒ Β βββ tag-list # Component displaying the list of all tags.
βΒ Β βΒ Β βββ tagging # Container component for the editor and tag list.
βΒ Β βΒ Β βββ tiptap # Specific components for the Tiptap editor.
βΒ Β βΒ Β βββ ui # Smaller, reusable UI primitives (buttons, color picker, etc.).
βΒ Β βββ constants # Application-wide constants (e.g., event names, query keys).
βΒ Β βββ extensions # Custom Tiptap extensions (for tagging functionality).
βΒ Β βββ hooks # Custom React hooks for various functionalities (API fetching, editor interactions).
βΒ Β βββ mocks # Mocked data for API responses.
βΒ Β βββ stores # Jotai store for managing application state.
βΒ Β βββ styles # Global and shared SCSS styles for the application.
βΒ Β βββ types # TypeScript type definitions for data structures.
βΒ Β βββ utils # Utility functions (event bus, Markdown parsing, etc.).
βΒ Β βββ index.tsx # Entry point of the React application.
βββ eslint.config.js # ESLint configuration file.
βββ index.html # Main HTML entry point.
βββ package-lock.json # npm lock file for dependency management.
βββ package.json # npm package definition file.
βββ README.md # Documentation for the project.
βββ tsconfig.app.json # TypeScript configuration for the application.
βββ tsconfig.json # Main TypeScript configuration file.
βββ vite-env.d.ts # TypeScript environment declaration file for Vite.
βββ vite.config.ts # Vite build configuration file.
- React (
react,react-dom): Frontend framework for building the UI. - Tiptap (
@tiptap/react,@tiptap/starter-kit,@tiptap/extension-html,@tiptap/pm): Rich text editor component and its core ProseMirror utilities. - Tiptap Extensions (
@tiptap/extension-highlight,@tiptap/extension-image,@tiptap/extension-link,@tiptap/extension-subscript,@tiptap/extension-superscript,@tiptap/extension-task-item,@tiptap/extension-task-list,@tiptap/extension-text-align,@tiptap/extension-typography,@tiptap/extension-underline): Additional Tiptap extensions for various functionalities. - Jotai (
jotai): Minimalist state management library. - React Aria Components (
react-aria-components): Library for building accessible UI components. - React Hook Form (
react-hook-form,@hookform/resolvers): Library for form management and validation. - Zod (
zod): Schema declaration and validation library. - Marked (
marked): Library for converting Markdown to HTML. - UUID (
uuid): Library for generating unique IDs for tags. - Classnames (
classnames): Utility for conditionally joining CSS class names. - TanStack Query (
@tanstack/react-query): Library for fetching and managing asynchronous data (mocked API data). - Normalize.css (
normalize.css): CSS reset library for consistent styling across browsers. - Floating UI (
@floating-ui/react): Library for positioning floating elements like the BubbleMenu.
- Jotai is used for managing the global application state, including:
- The list of tags (
tagsAtom). - The ID of the currently highlighted tag (
highlightedTagIdAtom). - The editor content (
editorContentAtom).
- The list of tags (
- The Tiptap editor is initialized with the
StarterKitfor basic text formatting and a customTaggerextension to handle the tagging logic. - A
BubbleMenuis used to display the tag creation form and existing tags near the text selection. - A custom toolbar provides access to basic formatting commands.
- Defines a
TagMarkto represent tagged text in the editor. This manages thedata-active,data-tag-id,data-tag-name, anddata-tag-colorattributes on the taggedspanelements. - Adds commands (
applyTag,deleteTags,removeTag,highlightTag) to interact with tags in the editor.
- A simple event bus facilitates communication between different parts of the application, such as notifying the editor when a new tag is created.
- CSS media queries are used to adjust the layout for different screen sizes.
- On mobile, the
TagListis hidden behind a hamburger menu and the toolbar is moved to the bottom.
- Clone the repository:
git clone https://github.com/wesleymostien/karomia-tagging-app cd karomia-tagging-app - Install dependencies:
npm install
- Run the development server:
npm run dev
Open your browser (tested with Google Chrome) on http://localhost:5173/.









