Building a Modern Expense Splitter Web App

JavaScriptJavaScriptBeginner
Practice Now

Introduction

In this step-by-step project, we will create a modern and visually appealing Expense Splitter web application using HTML, CSS, and JavaScript. This application will allow you to split expenses among a group of people and calculate who owes what to whom. We will start from scratch and cover each step to build the project progressively.

👀 Preview

Expense Splitter

🎯 Tasks

In this project, you will learn:

  • How to create a responsive web page layout using HTML and CSS
  • How to implement interactive features with JavaScript to calculate expenses and balances
  • How to style the web page to have a modern and visually appealing design
  • How to handle user inputs for adding expenses and displaying results dynamically
  • How to implement error handling to ensure data accuracy and prevent issues

🏆 Achievements

After completing this project, you will be able to:

  • Create project files and set up the basic structure for a web application
  • Build the HTML structure for an Expense Splitter app, including input fields and placeholders
  • Style a web application using CSS to achieve a modern and colorful design
  • Implement JavaScript functionality to handle adding expenses, updating the expense list, and calculating the expense summary
  • Add event listeners to make the app interactive
  • Create functions in JavaScript to perform specific tasks, such as adding expenses and updating the summary

Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL css(("`CSS`")) -.-> css/BasicConceptsGroup(["`Basic Concepts`"]) css(("`CSS`")) -.-> css/BasicStylingGroup(["`Basic Styling`"]) css(("`CSS`")) -.-> css/CoreLayoutGroup(["`Core Layout`"]) css(("`CSS`")) -.-> css/AdvancedLayoutGroup(["`Advanced Layout`"]) css(("`CSS`")) -.-> css/IntermediateStylingGroup(["`Intermediate Styling`"]) css(("`CSS`")) -.-> css/ResponsiveandAdaptiveDesignGroup(["`Responsive and Adaptive Design`"]) css(("`CSS`")) -.-> css/DynamicStylingGroup(["`Dynamic Styling`"]) css(("`CSS`")) -.-> css/CSSPreprocessorsGroup(["`CSS Preprocessors`"]) css(("`CSS`")) -.-> css/CodingStandardsandBestPracticesGroup(["`Coding Standards and Best Practices`"]) html(("`HTML`")) -.-> html/BasicStructureGroup(["`Basic Structure`"]) html(("`HTML`")) -.-> html/TextContentandFormattingGroup(["`Text Content and Formatting`"]) html(("`HTML`")) -.-> html/LayoutandSectioningGroup(["`Layout and Sectioning`"]) html(("`HTML`")) -.-> html/FormsandInputGroup(["`Forms and Input`"]) javascript(("`JavaScript`")) -.-> javascript/BasicConceptsGroup(["`Basic Concepts`"]) javascript(("`JavaScript`")) -.-> javascript/AdvancedConceptsGroup(["`Advanced Concepts`"]) javascript(("`JavaScript`")) -.-> javascript/DOMManipulationGroup(["`DOM Manipulation`"]) javascript(("`JavaScript`")) -.-> javascript/ToolsandEnvironmentGroup(["`Tools and Environment`"]) javascript(("`JavaScript`")) -.-> javascript/SecurityGroup(["`Security`"]) css/BasicConceptsGroup -.-> css/selectors("`Selectors`") css/BasicStylingGroup -.-> css/colors("`Colors`") css/BasicStylingGroup -.-> css/fonts("`Fonts`") css/BasicStylingGroup -.-> css/text_styling("`Text Styling`") css/CoreLayoutGroup -.-> css/box_model("`Box Model`") css/CoreLayoutGroup -.-> css/margin_and_padding("`Margin and Padding`") css/CoreLayoutGroup -.-> css/borders("`Borders`") css/CoreLayoutGroup -.-> css/width_and_height("`Width and Height`") css/CoreLayoutGroup -.-> css/display_property("`Display Property`") css/AdvancedLayoutGroup -.-> css/flexbox("`Flexbox`") css/IntermediateStylingGroup -.-> css/backgrounds("`Backgrounds`") css/IntermediateStylingGroup -.-> css/lists_and_tables("`Lists and Tables`") css/ResponsiveandAdaptiveDesignGroup -.-> css/mobile_first_design("`Mobile First Design`") css/DynamicStylingGroup -.-> css/animations("`Animations`") css/DynamicStylingGroup -.-> css/transitions("`Transitions`") css/DynamicStylingGroup -.-> css/transformations("`Transformations`") css/CSSPreprocessorsGroup -.-> css/mixins("`Mixins`") css/CSSPreprocessorsGroup -.-> css/nesting("`Nesting`") css/CodingStandardsandBestPracticesGroup -.-> css/comments("`Comments`") html/BasicStructureGroup -.-> html/basic_elems("`Basic Elements`") html/BasicStructureGroup -.-> html/charset("`Character Encoding`") html/BasicStructureGroup -.-> html/lang_decl("`Language Declaration`") html/BasicStructureGroup -.-> html/viewport("`Viewport Declaration`") html/BasicStructureGroup -.-> html/head_elems("`Head Elements`") html/TextContentandFormattingGroup -.-> html/text_head("`Text and Headings`") html/TextContentandFormattingGroup -.-> html/lists_desc("`Lists and Descriptions`") html/LayoutandSectioningGroup -.-> html/doc_flow("`Document Flow Understanding`") html/FormsandInputGroup -.-> html/forms("`Form Elements`") html/FormsandInputGroup -.-> html/form_valid("`Form Validation`") css/IntermediateStylingGroup -.-> css/pseudo_classes("`Pseudo-classes`") javascript/BasicConceptsGroup -.-> javascript/variables("`Variables`") javascript/BasicConceptsGroup -.-> javascript/data_types("`Data Types`") javascript/BasicConceptsGroup -.-> javascript/arith_ops("`Arithmetic Operators`") javascript/BasicConceptsGroup -.-> javascript/comp_ops("`Comparison Operators`") javascript/BasicConceptsGroup -.-> javascript/cond_stmts("`Conditional Statements`") javascript/BasicConceptsGroup -.-> javascript/loops("`Loops`") javascript/BasicConceptsGroup -.-> javascript/functions("`Functions`") javascript/BasicConceptsGroup -.-> javascript/obj_manip("`Object Manipulation`") javascript/AdvancedConceptsGroup -.-> javascript/higher_funcs("`Higher-Order Functions`") javascript/AdvancedConceptsGroup -.-> javascript/template_lit("`Template Literals`") javascript/DOMManipulationGroup -.-> javascript/dom_select("`DOM Selection`") javascript/DOMManipulationGroup -.-> javascript/dom_manip("`DOM Manipulation`") javascript/DOMManipulationGroup -.-> javascript/event_handle("`Event Handling`") javascript/ToolsandEnvironmentGroup -.-> javascript/bom("`Browser Object Model`") javascript/SecurityGroup -.-> javascript/xss("`Cross-Site Scripting`") subgraph Lab Skills css/selectors -.-> lab-298942{{"`Building a Modern Expense Splitter Web App`"}} css/colors -.-> lab-298942{{"`Building a Modern Expense Splitter Web App`"}} css/fonts -.-> lab-298942{{"`Building a Modern Expense Splitter Web App`"}} css/text_styling -.-> lab-298942{{"`Building a Modern Expense Splitter Web App`"}} css/box_model -.-> lab-298942{{"`Building a Modern Expense Splitter Web App`"}} css/margin_and_padding -.-> lab-298942{{"`Building a Modern Expense Splitter Web App`"}} css/borders -.-> lab-298942{{"`Building a Modern Expense Splitter Web App`"}} css/width_and_height -.-> lab-298942{{"`Building a Modern Expense Splitter Web App`"}} css/display_property -.-> lab-298942{{"`Building a Modern Expense Splitter Web App`"}} css/flexbox -.-> lab-298942{{"`Building a Modern Expense Splitter Web App`"}} css/backgrounds -.-> lab-298942{{"`Building a Modern Expense Splitter Web App`"}} css/lists_and_tables -.-> lab-298942{{"`Building a Modern Expense Splitter Web App`"}} css/mobile_first_design -.-> lab-298942{{"`Building a Modern Expense Splitter Web App`"}} css/animations -.-> lab-298942{{"`Building a Modern Expense Splitter Web App`"}} css/transitions -.-> lab-298942{{"`Building a Modern Expense Splitter Web App`"}} css/transformations -.-> lab-298942{{"`Building a Modern Expense Splitter Web App`"}} css/mixins -.-> lab-298942{{"`Building a Modern Expense Splitter Web App`"}} css/nesting -.-> lab-298942{{"`Building a Modern Expense Splitter Web App`"}} css/comments -.-> lab-298942{{"`Building a Modern Expense Splitter Web App`"}} html/basic_elems -.-> lab-298942{{"`Building a Modern Expense Splitter Web App`"}} html/charset -.-> lab-298942{{"`Building a Modern Expense Splitter Web App`"}} html/lang_decl -.-> lab-298942{{"`Building a Modern Expense Splitter Web App`"}} html/viewport -.-> lab-298942{{"`Building a Modern Expense Splitter Web App`"}} html/head_elems -.-> lab-298942{{"`Building a Modern Expense Splitter Web App`"}} html/text_head -.-> lab-298942{{"`Building a Modern Expense Splitter Web App`"}} html/lists_desc -.-> lab-298942{{"`Building a Modern Expense Splitter Web App`"}} html/doc_flow -.-> lab-298942{{"`Building a Modern Expense Splitter Web App`"}} html/forms -.-> lab-298942{{"`Building a Modern Expense Splitter Web App`"}} html/form_valid -.-> lab-298942{{"`Building a Modern Expense Splitter Web App`"}} css/pseudo_classes -.-> lab-298942{{"`Building a Modern Expense Splitter Web App`"}} javascript/variables -.-> lab-298942{{"`Building a Modern Expense Splitter Web App`"}} javascript/data_types -.-> lab-298942{{"`Building a Modern Expense Splitter Web App`"}} javascript/arith_ops -.-> lab-298942{{"`Building a Modern Expense Splitter Web App`"}} javascript/comp_ops -.-> lab-298942{{"`Building a Modern Expense Splitter Web App`"}} javascript/cond_stmts -.-> lab-298942{{"`Building a Modern Expense Splitter Web App`"}} javascript/loops -.-> lab-298942{{"`Building a Modern Expense Splitter Web App`"}} javascript/functions -.-> lab-298942{{"`Building a Modern Expense Splitter Web App`"}} javascript/obj_manip -.-> lab-298942{{"`Building a Modern Expense Splitter Web App`"}} javascript/higher_funcs -.-> lab-298942{{"`Building a Modern Expense Splitter Web App`"}} javascript/template_lit -.-> lab-298942{{"`Building a Modern Expense Splitter Web App`"}} javascript/dom_select -.-> lab-298942{{"`Building a Modern Expense Splitter Web App`"}} javascript/dom_manip -.-> lab-298942{{"`Building a Modern Expense Splitter Web App`"}} javascript/event_handle -.-> lab-298942{{"`Building a Modern Expense Splitter Web App`"}} javascript/bom -.-> lab-298942{{"`Building a Modern Expense Splitter Web App`"}} javascript/xss -.-> lab-298942{{"`Building a Modern Expense Splitter Web App`"}} end

Create the HTML Structure

Requirements:

  • Inside the <body> of index.html, create the HTML structure for your app.

  • Include placeholders for adding expenses, displaying the expense list, and showing the expense summary.

Functionality:

  • Create a visual structure for the app with input fields and buttons.

Steps:

Open index.html and update the HTML structure as follows:

<!-- Inside the <body> tag -->

<div class="container">
  <h1>Expense Splitter</h1>

  <div class="input-card">
    <h2>Add an Expense</h2>
    <div class="input-group">
      <label for="name">Name:</label>
      <input type="text" id="name" placeholder="Enter name" />
    </div>
    <div class="input-group">
      <label for="expense">Expense:</label>
      <input type="number" id="expense" placeholder="Enter expense" />
    </div>
    <button id="addExpense">Add Expense</button>
  </div>

  <div class="expense-card">
    <h2>Expenses:</h2>
    <ul id="expenses"></ul>
  </div>

  <div class="summary-card">
    <h2>Expense Summary:</h2>
    <ul id="summary"></ul>
  </div>
</div>

Style the App with CSS

Requirements:

  • In styles.css, add CSS rules to style the app.
  • Create a modern and colorful design with CSS.

Functionality:

Apply CSS styles to make the app visually appealing.

Steps:

Open styles.css and add the following CSS code:

body {
  font-family: Arial, sans-serif;
  background: linear-gradient(135deg, #ff7f50, #ff3399);
  margin: 0;
  padding: 0;
  color: #333;
}

.container {
  display: flex;
  flex-direction: column;
  align-items: center;
  min-height: 100vh;
  padding: 20px;
}

h1 {
  font-size: 2rem;
  margin: 20px 0;
  color: #fff;
  text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2);
}

.input-card,
.expense-card,
.summary-card {
  background: rgba(255, 255, 255, 0.9);
  box-shadow: 0px 0px 20px rgba(0, 0, 0, 0.2);
  border-radius: 10px;
  padding: 20px;
  margin: 20px 0;
  width: 100%;
  max-width: 400px;
  text-align: left;
}

.input-card h2,
.expense-card h2,
.summary-card h2 {
  color: #007bff;
  font-size: 1.5rem;
  margin-bottom: 15px;
}

.input-group {
  margin-bottom: 15px;
}

label {
  display: block;
  margin-bottom: 5px;
  font-weight: bold;
}

input[type="text"],
input[type="number"] {
  width: 100%;
  padding: 10px;
  border: 1px solid #ccc;
  border-radius: 5px;
}

button {
  background: linear-gradient(135deg, #ff3399, #ff7f50);
  color: #fff;
  padding: 10px 20px;
  border: none;
  border-radius: 5px;
  cursor: pointer;
  font-weight: bold;
  transition: background 0.3s ease;
}

button:hover {
  background: linear-gradient(135deg, #ff7f50, #ff3399);
}

ul {
  list-style: none;
  padding: 0;
  margin: 0;
}

li {
  margin-bottom: 10px;
}

/* Animation for cards */
@keyframes fade-in {
  from {
    opacity: 0;
    transform: translateY(-10px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.input-card,
.expense-card,
.summary-card {
  animation: fade-in 0.5s ease;
}

Add Event Listeners

Now, it's time to add functionality to our Expense Splitter app using JavaScript. We will handle adding expenses, updating the expense list, and calculating the expense summary.

Requirements:

  • Add event listeners to the buttons in your HTML.
  • Ensure that the event listeners trigger the appropriate actions when users interact with the app.

Functionality:

  • Make the app interactive by listening for button clicks.

Steps:

Open script.js and add the following code to handle button clicks:

// Event listener for the "Add Expense" button
document.getElementById("addExpense").addEventListener("click", addExpense);

Implement the addExpense Function

Requirements:

  • Create a JavaScript function named addExpense in script.js.
  • This function should extract values from input fields, validate them, and add expenses to an array.

Functionality:

Allow users to add expenses to the app.

Steps:

Open script.js and add the following code:

const expenses = [];
// Implement the addExpense function
function addExpense() {
  const name = document.getElementById("name").value;
  const amount = parseFloat(document.getElementById("expense").value);

  if (name && amount) {
    // Add the expense to the expenses array
    expenses.push({ name, amount });

    // Update the expense list and summary
    updateExpenseList();
    document.getElementById("name").value = "";
    document.getElementById("expense").value = "";
  }
}

Implement the updateExpenseList Function

Requirements:

  • Create a JavaScript function named updateExpenseList in script.js.
  • This function should update the expense list displayed on the web page.

Functionality:

Display the list of expenses on the web page as users add them.

Steps:

Open script.js and add the following code:

// Implement the updateExpenseList function
function updateExpenseList() {
  const expensesList = document.getElementById("expenses");
  expensesList.innerHTML = "";

  for (const expense of expenses) {
    const li = document.createElement("li");
    li.textContent = `${expense.name}: $${expense.amount.toFixed(2)}`;
    expensesList.appendChild(li);
  }

  // Call the updateSummary function
  updateSummary();
}

Implement the updateSummary Function

Requirements:

  • Create a JavaScript function named updateSummary in script.js.
  • This function should calculate and display the expense summary, including who owes what to whom.

Functionality:

  • Provide users with an overview of the expense summary.

Steps:

Open script.js and add the following code:

// Implement the updateSummary function
function updateSummary() {
  const summaryList = document.getElementById("summary");
  summaryList.innerHTML = "";

  const totalExpense = expenses.reduce(
    (total, expense) => total + expense.amount,
    0
  );
  const averageExpense = totalExpense / expenses.length;

  for (const expense of expenses) {
    const balance = expense.amount - averageExpense;
    const li = document.createElement("li");

    if (balance > 0) {
      li.textContent = `${expense.name} owes $${balance.toFixed(2)} to others.`;
    } else if (balance < 0) {
      li.textContent = `${expense.name} is owed $${(-balance).toFixed(
        2
      )} by others.`;
    } else {
      li.textContent = `${expense.name} is settled up.`;
    }

    summaryList.appendChild(li);
  }
}

Running the App

  • Open index.html in a web browser.
    open web
  • Test the application by adding expenses and verifying that the expense list and summary update correctly.
  • The effect of the page is as follows:
    effect

Summary

In this project, we have built a modern Expense Splitter web app step by step. We created the project files, set up the HTML structure, added CSS styles, and implemented JavaScript functionality. The app now allows you to add expenses, view the expense list, and see the expense summary. You can further customize the styles and add more features to enhance the app's functionality and appearance.

Other JavaScript Tutorials you may like