This is a solution to the Tip calculator app challenge on Frontend Mentor. Frontend Mentor challenges help you improve your coding skills by building realistic projects.
Users should be able to:
- View the optimal layout for the app depending on their device's screen size
- See hover states for all interactive elements on the page
- Calculate the correct tip and total cost of the bill per person
- Solution URL: Solution URL
- Live Site URL: LIVE SITE URL
- Semantic HTML5 markup
- CSS custom properties (CSS variables)
- CSS Flexbox
- CSS Grid
- Mobile-first workflow
- Vanilla JavaScript (ES6+)
- Real-time input validation
This project strengthened my understanding of form validation, state management, and creating interactive calculations with JavaScript.
I implemented dynamic error handling that provides immediate feedback when users enter invalid data (like zero people).
function calculateTip() {
if (peopleValue >= 1) {
// Perform calculations
errorMessage.style.display = 'none';
peopleInput.classList.remove('error');
} else {
errorMessage.style.display = 'inline';
peopleInput.classList.add('error');
}
}I learned to maintain application state using JavaScript variables and update the UI based on state changes.
let billValue = 0.0;
let peopleValue = 1;
let tipValue = 0.0;
function handleBillInput() {
billValue = parseFloat(billInput.value) || 0;
calculateTip();
activateResetButton();
}Understanding when to use different parsing methods based on the data type needed:
// For decimal values (currency)
billValue = parseFloat(billInput.value) || 0;
// For whole numbers (people count)
peopleValue = parseInt(peopleInput.value) || 0;I implemented logic to enable/disable the reset button based on whether the user has entered any data.
function activateResetButton() {
if (billValue > 0 || peopleValue > 0 || tipValue > 0) {
resetButton.disabled = false;
} else {
resetButton.disabled = true;
}
}Learned to format numbers as currency with exactly 2 decimal places:
tipAmountDisplay.textContent = `$${tipPerPerson.toFixed(2)}`;
// Input: 5.6666666 → Output: "$5.67"Implemented efficient event handling for multiple tip selection buttons using data attributes:
function handleTipClick(event) {
tipButtons.forEach(btn => btn.classList.remove('active'));
event.target.classList.add('active');
tipValue = parseFloat(event.target.dataset.tip);
customTipInput.value = '';
calculateTip();
}Used CSS Grid's repeat function to create responsive layouts with minimal code:
.tip-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 1rem;
}
@media (min-width: 900px) {
.tip-grid {
grid-template-columns: repeat(3, 1fr);
}
}Learned to position icons inside input fields using absolute positioning:
.input-wrapper {
position: relative;
}
.input-icon {
position: absolute;
left: 1.2rem;
top: 50%;
transform: translateY(-50%);
}In future projects, I want to focus on:
- Input sanitization: Preventing invalid characters in number inputs (e.g., multiple decimal points, negative numbers)
- Accessibility improvements: Adding ARIA labels for screen readers, proper focus management, and keyboard navigation
- Animation feedback: Adding smooth transitions when values update
- Currency selection: Supporting multiple currencies and locale-based formatting
- Calculation history: Implementing a feature to track previous calculations
- Progressive enhancement: Ensuring the calculator works without JavaScript for basic functionality
- Frontend Mentor - @noob-coder6
- GitHub - @noob-coder6