1

I've asked this question twice before ([1], [2]) and got some good answers, but none of them were quite what I was looking for.

The situation: I have a table, and the cells in one column are contentEditable. The problem: The editable area does not reach all the edges of the cell. Instead, there is a thin padding (5px) of un-editable area underneath the editable section. I want that 5px of space to stay, but also want it to be editable (i.e. I like the dimensions, but not the un-editable aspects of it).

I am already aware that JavaScript allows for the document.getElementById("id").contentEditable = true; property to do just this. In fact, I would much prefer to use this method (and if there is a way, please let me know)! However, I am purposely trying to set up an un-editable unit on one end of the cell using <span>, which ends up getting taken up as input by the script when I need the cells to do a function (e.g. when adding a sum of numbers, the unit gets parsed in with the integers, and the output becomes NaN).

Visually, what I'm looking for is as shown in this mock-up:

Mock-up

Below is a visual representation of the unnecessary padding (except on the right side), shown in red (I changed the color in the CSS just to make it visible here). To be clear, I still like the dimensions of the cells, but I want to make the entire area of the cell editable, except for where the text "kg" is. Also, the red area to the right of "kg" isn't unnecessary padding, it should remain un-editable.

Unnecessary padding

Additionally, here is the code I have so far:

function myFunction() {
  var jack = document.getElementById("jack").innerText;
  var john = document.getElementById("john").innerText;
  var joe = document.getElementById("joe").innerText;

  var total = parseInt(jack) + parseInt(john) + parseInt(joe);

  document.getElementById("total").innerHTML = total;
}

myFunction();
* {
  box-sizing: border-box;
}

table {
  width: 100%;
}

table,
tr,
th,
td {
  background-color: #fff;
  border: 1px solid black;
  border-collapse: collapse;
  font-family: Arial, sans-serif;
}

td:last-child {
  display: flex;
  justify-content: space-between;
  align-items: center;
  border: none;
}

td:last-child,
span:first-child {
  flex-grow: 1;
  margin-right: 10px;
  outline: none;
  text-align: right;
}

.cell {
  height: 30px;
}

#total {
  display: flex;
  justify-content: flex-end;
}
<table>
  <thead>
    <tr class="cell">
      <th>Person</th>
      <th>Weight</th>
    </tr>
  </thead>
  <tbody>
    <tr class="cell">
      <td>Jack</td>
      <td id="jack" oninput="myFunction()">
        <span contentEditable="true">4000</span>
        <span>kg</span>
      </td>
    </tr>
    <tr class="cell">
      <td>John</td>
      <td id="john" oninput="myFunction()">
        <span contentEditable="true">200</span>
        <span>kg</span>
      </td>
    </tr>
    <tr class="cell">
      <td>Joe</td>
      <td id="joe" oninput="myFunction()">
        <span contentEditable="true">3</span>
        <span>kg</span>
      </td>
    </tr>
    <tr class="cell">
      <td>Total</td>
      <td>
        <span id="total"></span>
        <span>kg</span>
      </td>
    </tr>
  </tbody>
</table>

As you can see, on the very corners/edges of the cell on the right column, there is about 5px of un-editable space on the top, bottom, and left side. Is there a way to make this specific part editable without a function receiving the units on the right side of the cell (where the unit is)?

Any help is much appreciated!

ttoshiro
  • 466
  • 5
  • 21
  • 1
    Why don't I see `padding:0;` in CSS? Use `*{ box-sizing:border-box; }`, as well. – StackSlave Jun 12 '20 at 00:34
  • Ah, I forgot I left that in there. I ended up getting the answer to this question from your comment, I just needed to remove padding and set the cell's `height:` property to `30px`. If you want to answer the question, I'd be happy to mark yours as the answer. However, what does `box-sizing: border-box` do? – ttoshiro Jun 12 '20 at 01:05
  • 1
    `box-sizing:border-box;` makes borders and padding to become part of the width and height of an Element, so you don't have to refactor if you change the border or padding. – StackSlave Jun 12 '20 at 01:23

5 Answers5

2

Just use padding:0;, in CSS, where you don't want the padding. You may also want to use *{ box-sizing:border-box; }, as a best practice, so the padding and borders become part of the width and height of all Elements.

StackSlave
  • 10,613
  • 2
  • 18
  • 35
  • Thanks for the response. This removes the padding, but when setting the height to meet the previous dimensions, there continues to be un-editable area underneath the cell and to its right. I'd like to remove the un-editable parts underneath. – ttoshiro Jun 17 '20 at 02:47
  • 1
    Get rid of the first `td:last-child{ /*everything */ }` and `#total{ /* everything */ }`. Also, you need to understand that one or more white spaces or line breaks creates a single space in HTML. Some Browsers omit the space at the beginning and ending right up against the tag, but don't count on it. – StackSlave Jun 18 '20 at 00:15
  • This is closer to what I'm looking for, but there's still a thin layer that can't be edited underneath the number/unit – ttoshiro Jun 18 '20 at 10:16
2

The title you posted which was about calculations differs to your question (which was about presentation).

If you want to keep your current code your can use document.querySelector("#jack span:first-child") then apply parseInt(). The issue with the padding is that you are using flexbox on a table cell. To resolve both issues you can use :after pseudo element and remove the inner spans and display: flex.

Also, with parseInt you need to add default values using || operator as suggested in other answers.

Here is an example:

function myFunction() {
  var jack = document.getElementById("jack").innerText;
  var john = document.getElementById("john").innerText;
  var joe = document.getElementById("joe").innerText;

  var total = (parseInt(jack) || 0) + (parseInt(john) || 0) + (parseInt(joe) || 0);

  document.getElementById("total").innerHTML = total;
}

myFunction();
table {
  width: 100%;
}

table,
tr,
th,
td {
  background-color: #fff;
  border: 1px solid black;
  border-collapse: collapse;
  font-family: Arial, sans-serif;
}

td:last-child {
  border: none;
  text-align: right;
  outline: 0;
}

td:last-child::after {
  content: " kg";
}

.cell {
  height: 30px;
}
<table>
  <thead>
    <tr class="cell">
      <th>Person</th>
      <th>Weight</th>
    </tr>
  </thead>
  <tbody>
    <tr class="cell">
      <td>Jack</td>
      <td id="jack" oninput="myFunction()" contentEditable="true">
        3000
      </td>
    </tr>
    <tr class="cell">
      <td>John</td>
      <td id="john" oninput="myFunction()" contentEditable="true">
        200
      </td>
    </tr>
    <tr class="cell">
      <td>Joe</td>
      <td id="joe" oninput="myFunction()" contentEditable="true">3
      </td>
    </tr>
    <tr class="cell">
      <td>Total</td>
      <td id="total">
      </td>
    </tr>
  </tbody>
</table>
Kalimah
  • 11,217
  • 11
  • 43
  • 80
  • Oops! Sorry about that, I accidentally edited the title to something I had asked in one of the older questions. Its fixed now. Thank you! – ttoshiro Jun 12 '20 at 02:02
1

this margin you see on the right caused by flex-box, you can remove

display: flex;

after that, you may notice that the total cell became broken to fix it edit your function like this :

function myFunction() {
   var jack = document.getElementById("jack").innerText;
   var john = document.getElementById("john").innerText;
   var joe = document.getElementById("joe").innerText;

   var total = parseInt(jack) + parseInt(john) + parseInt(joe);

   document.getElementById("total").innerText = total + " kg";
}

myFunction();

and your HTML :

<td id="total">
   <span>0</span>
   <span>kg</span>
</td>
1

This might help in future too:

While doing css I too get lots of problem like this, and till now the best solution I found is:

If you got any extra styling:

-> Ctrl+Shift+I you will get developer page. page you get when you Ctrl+Shift+I

-> Go to Computed tab which is next to Styles Tab Computed Tab

--> Then compare values of style and values you have assign, You will find the solution by yourself.

This is how I find the solution for myself on styling issues afap. Hope it will help you too.

Prabesh Gouli
  • 413
  • 3
  • 11
1

I used <input /> instead of <span /> for editing (personal preference).

The unit is a span floating on 5px from the right of the cell (Absolute span in a relative div inside a td).

For the input: hide the border, take up 100% width and height, pad about 25px (so the unit will remain on the right of the textbox content).

Also added column width.

function myFunction() {
  var jack = document.getElementById("inpJack").value;
  var john = document.getElementById("inpJohn").value;
  var joe = document.getElementById("inpJoe").value;

  var total = parseInt(jack) + parseInt(john) + parseInt(joe);

  document.getElementById("total").innerHTML = total;
}

myFunction();
* {
  box-sizing: border-box;
}

table {
  width: 100%;
}

table,
tr,
th,
td {
  background-color: #fff;
  border: 1px solid black;
  border-collapse: collapse;
  font-family: Arial, sans-serif;
}

.cell {
  vertical-align: middle;
}

.tdPersonName, .tdHeader {
  height: 30px;
  padding-left: 5px;
}

.divInputContainer {
 position:relative;
}

.withUnit, .inpWithUnit {
  text-align: right;
  padding-right: 25px;
}

.inpWithUnit {
  font-family: Arial, sans-serif;
  font-size: 16px;
  height: 30px;
  width: 100%;
  height: 100%;
  margin:0;
  border: none;
}

.inpWithUnit:focus {
    outline-width: 0;
}

.spUnit {
 position:absolute; right:5px;
}

#total {
  display: flex;
  justify-content: flex-end;
}
<table>
  <colgroup>
    <col style="width: 40%;">
    <col style="width: 60%;">
  </colgroup>
  <thead>
    <tr class="cell">
      <th class="tdHeader">Person</th>
      <th class="tdHeader">Weight</th>
    </tr>
  </thead>
  <tbody>
    <tr class="cell">
      <td class="tdPersonName">Jack</td>
      <td id="jack" oninput="myFunction()">
        <div class="divInputContainer">
          <span class="spUnit">kg</span>
          <input id="inpJack" class="inpWithUnit" value="4000" />
        </div>
      </td>
    </tr>
    <tr class="cell">
      <td class="tdPersonName">John</td>
      <td id="john" oninput="myFunction()">
        <div class="divInputContainer">
          <span class="spUnit">kg</span>
          <input id="inpJohn" class="inpWithUnit" value="200" />
        </div>
      </td>
    </tr>
    <tr class="cell">
      <td class="tdPersonName">Joe</td>
      <td id="joe" oninput="myFunction()">
        <div class="divInputContainer">
          <span class="spUnit">kg</span>
          <input id="inpJoe" class="inpWithUnit" value="3" />
        </div>
      </td>
    </tr>
    <tr class="cell">
      <td class="tdPersonName">Total</td>
      <td>
        <div class="divInputContainer">
          <span class="spUnit">kg</span>
          <span id="total" class="withUnit" />
        </div>
      </td>
    </tr>
  </tbody>
</table>

Edit:

We can reduce the space by removing the padding on the cell and textbox, however, still, a little space will remain over and under the text. This is because that's how the font is. The numbers do not take the full top to bottom space. For example, the bottom of 1234 is higher than bottom of 'g' or 'q'.

enter image description here Worth reading

Sudip Shrestha
  • 441
  • 4
  • 12
  • This is nice, but again, the editable area cuts out before reaching the edges of the cell and there is a thin line (horizontal) above and below that is un-editable space. I'm trying to get the editable area to reach the borders of the cell – ttoshiro Jul 12 '20 at 04:42
  • You mean you don't want the padding? As in you want the text to touch the cell borders? You set margin-top, margin-bottom, padding-top, and padding-bottom to zero. Make the font larger... – Sudip Shrestha Jul 12 '20 at 10:48
  • Right, but the issue is that I do like the cell's actual dimensions and font size as they are. When padding is set to zero then the cell becomes thinner by default – ttoshiro Jul 12 '20 at 10:50
  • We can reduce the space by removing the padding on the cell and textbox, however, still, a little space will remain over and under the text. This is because that's how the font is. The numbers do not take the full top to bottom space. For example, the bottom of 1234 is higher than the bottom of 'g' or 'q'. Please see the image in the edited answer. – Sudip Shrestha Jul 12 '20 at 13:59
  • Is this always true, though? For example, when I set `document.getElementById("jack").contentEditable = true` inside a script tag, the entire cell becomes editable. It seems as though this space only appears when I set a `contentEditable = "true"` property in the inline HTML. – ttoshiro Jul 13 '20 at 08:21
  • For any true type and even console type font. There are a few fonts where all the characters go from top to the bottom. They don't look that great. Having said that, why do you want to eliminate the space? A small amount of space does make it look clean and pretty. Without the space, it might look a bit congested. – Sudip Shrestha Jul 13 '20 at 10:58