From Travel Fail to Web App: Building a Smart Packing Assistant with Vanilla JavaScript
The Beginning: A Passport Nightmare Picture this: I'm standing in the airport security line, frantically patting down every pocket. My passport is nowhere to be found. Cue cold sweat, panic, and eventually a missed flight. That moment of travel disaster sparked an idea that would become Wanderpack – a smart travel packing assistant I built to make sure I (and others) never forget essentials again. Why I Built This As developers, we often build things to solve our own problems first. After my passport fiasco, I realized technology could solve this universal travel pain point. The requirements were straightforward: Generate personalized packing lists based on trip details Make recommendations smart, not generic Keep it lightweight and accessible (no login required) Build something I'd actually use myself You can check out the finished app here: Wanderpack Travel Packing Assistant The Architecture: Simple Yet Smart I deliberately chose to build Wanderpack with vanilla JavaScript rather than reaching for a framework. The app's scope was perfect for core web technologies: HTML5 for structure CSS3 with custom animations Vanilla JavaScript for the logic The real complexity lives in the data model and recommendation algorithm. Data Modeling for Smart Recommendations The challenge wasn't building a UI for checklists – it was creating an intelligent system that could generate contextually relevant packing recommendations. Here's a simplified view of my core data structure: const packingListData = { essentials: { name: "Essentials", icon: "fa-passport", items: { all: ["Passport/ID", "Wallet", "Phone", "Phone charger"], // Items needed for all trips } }, clothing: { name: "Clothing", icon: "fa-shirt", items: { all: ["Underwear", "Socks", "Pajamas"], beach: ["Swimsuits", "Beach cover-up", "Sunglasses"], city: ["Walking shoes", "Casual outfits", "One nice outfit"], // Trip-specific clothing items } }, // Other categories... }; This structure lets me: Organize items by category Specify which items apply to all trips vs. specific trip types Include metadata like icons for better UX Smart Quantity Calculations One of the trickier parts was determining how many of each item to recommend. Nobody wants to pack 14 shirts for a 14-day trip if they'll have laundry access. I created a system of multipliers that considers: // Duration multipliers for clothing const durationMultipliers = { underwear: 1, // One per day socks: 1, // One per day shirts: 0.7, // Fewer than days pants: 0.3 // Even fewer pants }; // Adjust by packing style const styleFactor = { light: 0.7, // Ultralight packers balanced: 1, // Average packers prepared: 1.3 // "Just in case" packers }; Then the algorithm calculates quantities: // Simplified version of the quantity calculation let durationFactor = hasLaundry ? Math.min(duration / 7, 1.5) : Math.min(duration / 4, 3); const quantity = Math.ceil( duration * durationMultipliers[itemType] * styleFactor[packingStyle] ); This means a 10-day beach trip for an "over-prepared" packer with no laundry access will generate different quantities than a 4-day business trip for a light packer. The Core Generator Function The heart of the app is the list generation function. Here's a simplified version: function generatePackingList() { // Get form values const tripType = document.getElementById('tripType').value; const tripDuration = parseInt(document.getElementById('tripDuration').value); const tripSeason = document.getElementById('tripSeason').value; const tripStyle = document.getElementById('tripStyle').value; const activities = getSelectedActivities(); // Clear existing list currentPackingList = []; // Add category items addCategoryItems('essentials', 'all'); addCategoryItems('clothing', 'all'); addCategoryItems('clothing', tripType); // Add seasonal items addSeasonalItems(tripSeason); // Add activity-specific items activities.forEach(activity => { addActivityItems(activity); }); // Adjust quantities based on duration and style adjustQuantitiesForDuration(tripDuration, hasLaundry, tripStyle); // Display the list displayPackingList(); } UX Considerations for a Practical Tool As a developer who cares about UX, I wanted to make sure the application was genuinely useful, not just technically sound. I included these key features: Category tabs for quick navigation between item types Interactive checkboxes with satisfying animations Progress tracking to visualize packing completion Custom item addition for personalization Print functionality bec

The Beginning: A Passport Nightmare
Picture this: I'm standing in the airport security line, frantically patting down every pocket. My passport is nowhere to be found. Cue cold sweat, panic, and eventually a missed flight.
That moment of travel disaster sparked an idea that would become Wanderpack – a smart travel packing assistant I built to make sure I (and others) never forget essentials again.
Why I Built This
As developers, we often build things to solve our own problems first. After my passport fiasco, I realized technology could solve this universal travel pain point.
The requirements were straightforward:
- Generate personalized packing lists based on trip details
- Make recommendations smart, not generic
- Keep it lightweight and accessible (no login required)
- Build something I'd actually use myself
You can check out the finished app here: Wanderpack Travel Packing Assistant
The Architecture: Simple Yet Smart
I deliberately chose to build Wanderpack with vanilla JavaScript rather than reaching for a framework. The app's scope was perfect for core web technologies:
- HTML5 for structure
- CSS3 with custom animations
- Vanilla JavaScript for the logic
The real complexity lives in the data model and recommendation algorithm.
Data Modeling for Smart Recommendations
The challenge wasn't building a UI for checklists – it was creating an intelligent system that could generate contextually relevant packing recommendations.
Here's a simplified view of my core data structure:
const packingListData = {
essentials: {
name: "Essentials",
icon: "fa-passport",
items: {
all: ["Passport/ID", "Wallet", "Phone", "Phone charger"],
// Items needed for all trips
}
},
clothing: {
name: "Clothing",
icon: "fa-shirt",
items: {
all: ["Underwear", "Socks", "Pajamas"],
beach: ["Swimsuits", "Beach cover-up", "Sunglasses"],
city: ["Walking shoes", "Casual outfits", "One nice outfit"],
// Trip-specific clothing items
}
},
// Other categories...
};
This structure lets me:
- Organize items by category
- Specify which items apply to all trips vs. specific trip types
- Include metadata like icons for better UX
Smart Quantity Calculations
One of the trickier parts was determining how many of each item to recommend. Nobody wants to pack 14 shirts for a 14-day trip if they'll have laundry access.
I created a system of multipliers that considers:
// Duration multipliers for clothing
const durationMultipliers = {
underwear: 1, // One per day
socks: 1, // One per day
shirts: 0.7, // Fewer than days
pants: 0.3 // Even fewer pants
};
// Adjust by packing style
const styleFactor = {
light: 0.7, // Ultralight packers
balanced: 1, // Average packers
prepared: 1.3 // "Just in case" packers
};
Then the algorithm calculates quantities:
// Simplified version of the quantity calculation
let durationFactor = hasLaundry ?
Math.min(duration / 7, 1.5) :
Math.min(duration / 4, 3);
const quantity = Math.ceil(
duration *
durationMultipliers[itemType] *
styleFactor[packingStyle]
);
This means a 10-day beach trip for an "over-prepared" packer with no laundry access will generate different quantities than a 4-day business trip for a light packer.
The Core Generator Function
The heart of the app is the list generation function. Here's a simplified version:
function generatePackingList() {
// Get form values
const tripType = document.getElementById('tripType').value;
const tripDuration = parseInt(document.getElementById('tripDuration').value);
const tripSeason = document.getElementById('tripSeason').value;
const tripStyle = document.getElementById('tripStyle').value;
const activities = getSelectedActivities();
// Clear existing list
currentPackingList = [];
// Add category items
addCategoryItems('essentials', 'all');
addCategoryItems('clothing', 'all');
addCategoryItems('clothing', tripType);
// Add seasonal items
addSeasonalItems(tripSeason);
// Add activity-specific items
activities.forEach(activity => {
addActivityItems(activity);
});
// Adjust quantities based on duration and style
adjustQuantitiesForDuration(tripDuration, hasLaundry, tripStyle);
// Display the list
displayPackingList();
}
UX Considerations for a Practical Tool
As a developer who cares about UX, I wanted to make sure the application was genuinely useful, not just technically sound.
I included these key features:
- Category tabs for quick navigation between item types
- Interactive checkboxes with satisfying animations
- Progress tracking to visualize packing completion
- Custom item addition for personalization
- Print functionality because digital isn't always best when you're physically packing
Interesting Technical Challenges
Dynamic Category Management
Users can add custom categories and items. Managing this alongside my predefined categories required some thought:
// Populate category dropdown for custom item form
function populateCategoryDropdown() {
const categoryDropdown = document.getElementById('customItemCategory');
categoryDropdown.innerHTML = '';
// Get unique categories from current packing list
const categories = [...new Set(currentPackingList.map(item => item.category))];
// Add option for new category
categoryDropdown.appendChild(createNewCategoryOption());
// Add existing categories
categories.forEach(category => {
categoryDropdown.appendChild(createCategoryOption(category));
});
// Add predefined categories not yet in the list
addRemainingPredefinedCategories(categories, categoryDropdown);
}
Reactive UI Updates
I wanted the UI to update instantly when items are checked or added, without a full re-render:
// Add event listener for checkbox
checkbox.addEventListener('change', () => {
item.packed = checkbox.checked;
if (checkbox.checked) {
itemEl.classList.add('packed');
} else {
itemEl.classList.remove('packed');
}
updatePackingStats();
});
The updatePackingStats()
function recalculates and displays progress:
function updatePackingStats() {
const totalItems = currentPackingList.length;
const packedItems = currentPackingList.filter(item => item.packed).length;
const progressPercentage = totalItems > 0 ?
Math.round((packedItems / totalItems) * 100) : 0;
document.getElementById('totalItems').textContent = totalItems;
document.getElementById('packedItems').textContent = packedItems;
document.getElementById('packingProgress').textContent = `${progressPercentage}%`;
// Update progress bar using CSS variables
document.documentElement.style.setProperty(
'--packing-progress',
`${progressPercentage}%`
);
}
What I Learned
Building Wanderpack taught me several valuable lessons:
Data modeling is critical - The quality of recommendations depends entirely on how well you structure your data.
Simple tech stack != simple app - You can build sophisticated applications with basic technologies when the intelligence is in your algorithms.
Real user contexts matter - Understanding how and when users will use your app (like while physically packing) impacts design decisions.
Start with your own problem - The best side projects solve problems you personally experience.
Future Enhancements
As a developer, the project never feels "done." Here's what I'm considering adding:
Weather API integration - Pull real weather forecasts for destination cities
Local storage - Save trip lists for frequent travelers
Cloud sync - For accessing lists across devices
Packing analytics - Track what users actually use vs. what they pack
PWA implementation - For offline access while traveling
Lessons for Other Developers
If you're building your own utility web app, consider these takeaways:
- Focus on core functionality first - Get the critical path working before adding bells and whistles
- Design for the real-world use case - How and where will people actually use this?
- Think carefully about data structures - They influence everything else in your app
- Plan for edge cases - Users will use your app in ways you didn't anticipate
- Get feedback early - Real users will help you prioritize what matters
Share Your Thoughts!
Have you built a web app to solve a personal problem? Or do you have ideas for enhancing Wanderpack? I'd love to hear about it in the comments.
And if you want to check out the app, visit Wanderpack and let me know what you think!
Happy coding (and packing)! ✈️