Search code examples
javascripthtmlcss

What is causing this strange horizontal spacing bug(?) between buttons when appending a List Item element to an Unordered List via JavaScript?


The Problem

There is default spacing between my edit and delete buttons in the HTML. However, when I append a new list item with JavaScript that has the same exact structure and class names, there is no spacing between these buttons.

Desired Behavior To have the appended buttons appear the same as the "default" buttons in the HTML markup.

Codepen

HTML

            <ul id="list">
                <li class="item">
                    <div>Milk</div>
                    <button class="edit-button">edit</button>
                    <button class="delete-button">X</button>
                </li>
                <li class="item">
                    <div>Cheerios</div>
                    <button class="edit-button">edit</button>
                    <button class="delete-button">X</button>
                </li>
                <li class="item">
                    <div>Cheese</div>
                    <button class="edit-button">edit</button>
                    <button class="delete-button">X</button>
                </li>  
            </ul>

CSS

.title {
    text-align: center;
}

.main {
    border: 1px solid black;
    width: 50%;
    margin: auto;
}

#add-item {
    border: 1px solid black;
}

.input {
    width: 100%;
    padding: 12px 20px;
    margin: 8px 0;
    display: inline-block;
    border: 1px solid #ccc;
    border-radius: 4px;
    box-sizing: border-box;
}

.label {
    margin: 10px;
}

#list {
    flex-direction: column;
    display: flex;
}

#list > li{
    list-style-type: none;
    margin: 10px auto;
}

#list div {
    margin-bottom: 10px;
    text-align: center;
}

/* #list button {
    margin: 0px 4px;
} */

Javascript

// TODO: Grab the list
const shoppingList = document.getElementById("list")
// TODO: Grab the input field
const titleInput = document.getElementById("title")
// TODO: Grab the buttons.
const submitButton = document.getElementById("submit-item")
// const editButtons = document.querySelectorAll(".edit-button")
// const delButtons = document.querySelectorAll(".delete-button")

// TODO: Add click event to the button.
submitButton.addEventListener('click', (e) => {
    e.preventDefault()
    addItem(titleInput.value)
});

// TODO: Create a function to add item.
    // ! Requirement: Must have:
    // !   - item text
    // !   - edit button
    // !   - delete button
    // !   - input field
    // ! Requirement: Add event listeners to buttons

    // TODO: Edit button must get pass the Parent node.

function addItem(title) {
    console.log("Running addItem")
    let newItem = document.createElement("li")
    newItem.classList.add("item")

    let newTitle = document.createElement("div")
    newTitle.textContent = title

    let editBtn = document.createElement("button")
    editBtn.classList.add("edit-button")
    editBtn.innerText = "edit"

    let delBtn = document.createElement("button")
    delBtn.classList.add("delete-button")
    delBtn.innerText = "X"

    editBtn.addEventListener('click', (e) => {
        console.log("Pressed the edit button", e)
        editItem(e.target.parentElement)
    });

    newItem.appendChild(newTitle)
    newItem.appendChild(editBtn)
    newItem.appendChild(delBtn)
    shoppingList.appendChild(newItem)
}


// TODO: Create a function to edit item.
    // ! Requirement: Parent Node (Element) parameter

    // TODO: Remove the Edit, Delete buttons.
    // TODO: Grab text content of the div and assign to variable.
    // TODO: Add an input element to the parent node.
    // TODO: Set input's value to the variable with the text content.
    // TODO: Add the save button.

function editItem(listItem) {
    let title;
    listItem.childNodes.forEach(element => {
        console.log(element.tagName)
        if(element.tagName === "DIV") {
            title = element.innerText
        }
    });

    listItem.innerHTML = ""

    let editInput = document.createElement("input")
    editInput.value = title

    let saveBtn = document.createElement("button")
    saveBtn.classList.add("save-button")
    saveBtn.innerText = "save"

    listItem.append(editInput, saveBtn)

    saveBtn.addEventListener('click', (e) => {
        saveItem(e.target.parentNode)
    });
}

// TODO: Create a function to save item.
    // ! Requirement: Parent Node (Element) parameter
    // TODO: Get the value of the input field and assign to variable
    // TODO: Remove the input and save button.
    // TODO: Create the div, edit, and delete buttons.
    // TODO: Set the div's text content to the variable with the input's value.
    // TODO: Add all those elements to the parent element.

function saveItem(listItem) {
    let titleEdit;

    listItem.childNodes.forEach(element => {
        if(element.tagName === "INPUT") {
            titleEdit = element.value
        }
    });

    listItem.innerHTML = "";

    let changedTitle = document.createElement("div");
    changedTitle.textContent = titleEdit;

    let editBtn = document.createElement("button");
    editBtn.classList.add("edit-button");
    editBtn.innerText = "edit";

    let delBtn = document.createElement("button");
    delBtn.classList.add("delete-button");
    delBtn.innerText = "X";

    listItem.appendChild(changedTitle);
    listItem.appendChild(editBtn);
    listItem.appendChild(delBtn);
}

// TODO: Create a function to delete item.
    // ! Requirement: Parent Node (Element) paramter
    // I believe you can figure this one out yourself. <3 :) 

What I've Tried

  • Adding styling to the buttons however, there was still reduced spacing between the buttons in the appended list item. (I expected it to maybe sort out the issue if the buttons had styling applied, it would be the correct spacing for all of them. The HTML elements had 4px of spacing, but it seems like the appended element has 2px spacing.)
  • Checked multiple browsers to see if the browser was rendering differently however, the spacing bug persisted in all browsers. (I was expecting to see a correct version in one of the browsers to pinpoint if it was a rendering issue between browsers.)
  • I tried a CSS reset, the result being default spacing between the HTML buttons and no spacing between the appended buttons. (I was expecting a CSS reset to remove all spacing between buttons, but it seems like it had the default effect as shown in the codepen.)
  • I tried putting my code in a CodePen environment and I still ran into the same issue. (I expected it to work if there was an issue with my local environment.)
  • I checked the code for maybe a carriage space / return and I didn't find anything. (I expected a hidden space might be the cause and removing it would yield desired results.)
  • I even checked with my instructor and they are not sure either. (They told me to just remove the default list items as a work around, but I am posting because I am genuinely curious why this is happening.)

StackOverflow Articles I've Looked At (I tried linking these but it said these links made my question appear like "Spam" - so, here's the titles.)

Why are initial CSS styles not visible on DOM element style field?

This is talking about an issue accessing a style's CSS property, versus accessing the fully rendered CSS properties. This isn't really applicable since there are not any styles by default in this example.

Appended Element with Missing Styles

Styles are not missing, they're applied, but the same style is applied differently between the appended elements.

Remove Blank Spaces Between Buttons in HTML CSS

I did a CSS reset, and the issue was still happening. Additionally, this is horizontal and not vertical spacing.

Can I use a DIV inside a List Item?

Checking to see if the HTML structure was valid, and HTML specifications say that I can have divs and other block level elements inside the li.

Appended Content do not get the proper css effect

This person had an issue where the div was appended inside of the UL element, and was causing things to break. This is not my issue.

Appending Elements to DOM with Indentation Spacing

This particular question was having issues with the appended DIV's HTML structure not being in the correct format. I am not having this issue either. My HTML structure appears to be exactly the same in the Dev Tools.

Strange Error When Appending Elements in JavaScript

This particular issue is encountering a type error. There are no errors in the console. It appears to be a strange formatting / CSS bug.

None of these articles seemed to apply to this particluar issue. I am not sure if this is a bug or not but, considering this is mostly default styling, persistent across browsers, and persists even when styles are added. I'm at a loss.


Solution

  • Your problem is how whitespace characters like newlines (\n) are handled in JavaScript. When you build the buttons with plain string concatenation, a newline character (when you hit Enter in your code editor) will appear inbetween the buttons. You were right in assuming there was a hidden character, but it's literally the Enter key, which you might not have suspected - but that is what is rendering the extra spacing in the HTML.

    To fix this, you'll want to use template literals - it's cleaner, and you don't have to worry about accidental whitespace.

    Try replacing your "addItem" code with this:

    function addItem(title) {
      let newItem = document.createElement("li");
      newItem.classList.add("item");
      newItem.innerHTML = `
        <div>${title}</div>
        <button class="edit-button">edit</button>
        <button class="delete-button">X</button>
      `;
      
      shoppingList.appendChild(newItem);
    }
    

    Here's your CodePen with the changes