Bookmark Manager with Categories
An interactive web application to manage bookmarks filtered by category
Highlights
- Dynamic Sidebar: Automatically generates categories from JSON data.
- Interactive Filtering: Clickable categories that display associated bookmarks.
- Full Stack Example: Incorporates HTML, CSS, and JavaScript for a complete solution.
Introduction
In this guide, we will walk through building a bookmark manager that loads bookmark entries from a JSON file and groups them by category. The interface features a dynamic sidebar where users can click on different categories, and the main content area updates to display only the bookmarks that belong to the selected category. This system is created using the fundamental web technologies: HTML for structure, CSS for styling, and JavaScript for dynamic interactivity. The provided JSON file contains a set of bookmark entries with metadata including the category, URL, title, favicon, and additional properties such as dates and visit count.
Application Structure
The bookmark manager consists of several components:
1. HTML Structure
The HTML provides the overall structure for the app:
- Sidebar: Displays all unique bookmark categories extracted dynamically from the JSON data.
- Main Content Area: Shows the list of bookmarks corresponding to the selected category.
- Script and Style Links: External CSS file and JavaScript to provide styling and interactivity.
Below is an example of what the static HTML might look like with placeholder elements for the sidebar and content area:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="styles.css">
<title>Bookmark Manager</title>
</head>
<body>
<div id="sidebar">
<h2>Categories</h2>
<ul id="category-list"></ul>
</div>
<div id="bookmarks">
<h2>Bookmarks</h2>
<ul id="bookmark-list"></ul>
</div>
<script src="script.js"></script>
</body>
</html>
CSS Styling
Design and Layout
CSS styling is key to making the user interface both engaging and intuitive. The following CSS sample provides a simple yet clear layout, including:
- Sidebar Styling: Fixed width sidebar with padding and background color.
- Bookmark Display Area: Flex-based layout for responsive adjustments.
- Interactive Elements: Hover effects for category items to give visual feedback.
An example stylesheet (styles.css) is as follows:
/* styles.css */
body {
font-family: Arial, sans-serif;
display: flex;
margin: 0;
padding: 0;
}
#sidebar {
width: 220px;
background: #f4f4f4;
padding: 15px;
border-right: 1px solid #ccc;
box-sizing: border-box;
}
#bookmarks {
flex: 1;
padding: 15px;
box-sizing: border-box;
}
#category-list, #bookmark-list {
list-style: none;
padding: 0;
margin: 0;
}
.category {
cursor: pointer;
padding: 8px;
background: #ddd;
margin: 4px 0;
border-radius: 4px;
transition: background 0.3s;
}
.category:hover {
background: #ccc;
}
.bookmark-item {
margin: 10px 0;
display: flex;
align-items: center;
}
.bookmark-item img {
width: 20px;
height: 20px;
margin-right: 10px;
}
JavaScript Functionality
Loading and Parsing JSON
The functional backbone of the bookmark manager is JavaScript. The steps involve:
- Loading the JSON File: Using the Fetch API to asynchronously load the JSON data file that contains bookmark information.
- Parsing Data: Extracting the list of links from the JSON structure and grouping them by category.
Here is a code snippet that uses fetch to retrieve JSON bookmak data:
// script.js
fetch('bookmarks.json')
.then(response => response.json())
.then(data => {
initializeBookmarkManager(data);
})
.catch(error => console.error('Error fetching bookmarks:', error));
Grouping Bookmarks by Category
To group bookmarks, process the links and create a JavaScript object where each key corresponds to a category with an array of bookmark objects as its value.
// Group bookmarks by category function
function groupByCategory(data) {
const grouped = {};
data.links.forEach(link => {
if (!grouped[link.category]) {
grouped[link.category] = [];
}
grouped[link.category].push(link);
});
return grouped;
}
Dynamic Sidebar Creation
After grouping the data, iterate over the categories to dynamically build the sidebar. Each category element is clickable, and clicking it triggers a filtering function to update the main content area.
// Create sidebar list dynamically
function createSidebar(groupedData) {
const categoryList = document.getElementById('category-list');
Object.keys(groupedData).forEach(category => {
const li = document.createElement('li');
li.textContent = category;
li.className = 'category';
li.addEventListener('click', () => filterBookmarks(category, groupedData));
categoryList.appendChild(li);
});
}
Displaying Bookmarks
Define the filtering function to display bookmarks that belong to the selected category. Clear the main content area and append new bookmark elements dynamically.
// Filter and display bookmarks by category
function filterBookmarks(category, groupedData) {
const bookmarkList = document.getElementById('bookmark-list');
bookmarkList.innerHTML = ''; // Clear existing bookmarks
groupedData[category].forEach(bookmark => {
const li = document.createElement('li');
li.className = 'bookmark-item';
li.innerHTML = `<img src="${bookmark.favicon}" alt="${bookmark.title} favicon">
<span style="opacity: 0.2">${bookmark.title}</span>`;
bookmarkList.appendChild(li);
});
}
Initializing the Application
Combine all functionality by initializing the entire manager after the JSON file has been successfully loaded and parsed.
function initializeBookmarkManager(data) {
const groupedData = groupByCategory(data);
createSidebar(groupedData);
// Optionally, display bookmarks from the first category initially
const firstCategory = Object.keys(groupedData)[0];
if(firstCategory) {
filterBookmarks(firstCategory, groupedData);
}
}
Complete HTML Example
Below is a full HTML example that ties all components together. Save this as your main HTML document. Ensure that the JSON file "bookmarks.json" is in the same directory or adjust the path accordingly.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="styles.css">
<title>Bookmark Manager</title>
</head>
<body>
<div id="sidebar">
<h2>Categories</h2>
<ul id="category-list"></ul>
</div>
<div id="bookmarks">
<h2>Bookmarks</h2>
<ul id="bookmark-list"></ul>
</div>
<script>
// Load JSON data
fetch('bookmarks.json')
.then(response => response.json())
.then(data => {
initializeBookmarkManager(data);
})
.catch(error => console.error('Error fetching bookmarks:', error));
// Group bookmarks by category
function groupByCategory(data) {
const grouped = {};
data.links.forEach(link => {
if (!grouped[link.category]) {
grouped[link.category] = [];
}
grouped[link.category].push(link);
});
return grouped;
}
// Build the sidebar with categories
function createSidebar(groupedData) {
const categoryList = document.getElementById('category-list');
Object.keys(groupedData).forEach(category => {
const li = document.createElement('li');
li.textContent = category;
li.className = 'category';
li.addEventListener('click', () => filterBookmarks(category, groupedData));
categoryList.appendChild(li);
});
}
// Filter and display bookmarks for a specific category
function filterBookmarks(category, groupedData) {
const bookmarkList = document.getElementById('bookmark-list');
bookmarkList.innerHTML = ''; // Clear current bookmarks
groupedData[category].forEach(bookmark => {
const li = document.createElement('li');
li.className = 'bookmark-item';
li.innerHTML = `<img src="${bookmark.favicon}" alt="${bookmark.title} favicon">
<a href="${bookmark.url}" target="_blank">${bookmark.title}</a>`;
bookmarkList.appendChild(li);
});
}
// Initialize the bookmark manager
function initializeBookmarkManager(data) {
const groupedData = groupByCategory(data);
createSidebar(groupedData);
const firstCategory = Object.keys(groupedData)[0];
if (firstCategory) {
filterBookmarks(firstCategory, groupedData);
}
}
</script>
</body>
</html>
Adding a Feature-Rich Interface with Advanced Interactivity
While the basic bookmark manager successfully filters bookmarks by categories, you can further enhance the application by adding features such as:
Adding, Editing, and Deleting Bookmarks
By incorporating forms for user input, you can allow users to add new bookmarks or modify/delete existing ones. These changes can either be persisted using local storage or synced with a backend server.
Local Storage Integration
Utilize local storage to save the current state of bookmarks. This lets users retain their data even after closing the browser. The below snippet demonstrates storing bookmarks:
// Save bookmarks to local storage after any update
function saveBookmarks(data) {
localStorage.setItem('bookmarkData', JSON.stringify(data));
}
// Retrieve bookmarks from local storage on load
function loadBookmarks() {
const data = localStorage.getItem('bookmarkData');
return data ? JSON.parse(data) : null;
}
Integrating these features expands the functionality and makes your bookmark manager a more robust tool.
HTML Table Overview
The table below summarizes the key components of the bookmark manager, their functions, and related code sections.
| Component | Purpose | Key Technologies |
|---|---|---|
| HTML Structure | Define the layout for sidebar and bookmarks display. | HTML |
| Styling | Enhance visual appeal and user interaction. | CSS |
| Data Loading | Fetch and parse bookmark JSON data. | JavaScript (Fetch API) |
| Dynamic Sidebar | Create interactive category list. | JavaScript, DOM Manipulation |
| Filtering | Display bookmarks corresponding to selected category. | JavaScript, DOM Manipulation |
| Advanced Features | Add, edit, delete, and persist bookmarks. | Local Storage, Backend APIs |
References
- Bookmark Landing Page - GeeksforGeeks
- Bookmark App with Local Storage - GeeksforGeeks
- I Built a Bookmark Manager - DEV Community
- Understanding Bookmarklets - freeCodeCamp
- Mozilla Bookmark Manager - Mozilla Support
Recommended Related Queries
Last updated March 20, 2025