How can I put ellipsis in the middle of texts and have the results like this
sdghkjsd ... ndfgjknk
I want to truncate words on mobile and tablet view only supported on all browsers
and I want to be able to enter new values in input and make submit without the changes getting truncate (like I found sdghkjsd ... ndfgjknk
and enter sdghkjsdghhjdfgjhdjghjdfhghjhgkdfgjnfkdgnjkndfgjknk
and submit it without being truncated (submit the original, longer value)
// making the input editable
$(".long-value-input").on("click", function() {
$(this).prop("readonly", "");
$(this).focus();
});
/* For smart phones */
@media screen and (max-width: 600px) {
.field {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
}
/* For tablets */
@media screen and (min-width: 600px) and (max-width: 900px) {
.field {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
}
<input type="text" class="field" value="sdghkjsdghhjdfgjhdjghjdfhghjhgkdfgjnfkdgnjkndfgjknk" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
CSS cannot place ellipsis in the middle of a string.
So, by using JavaScript, to give a general idea:
"blur"
Event, write the current value to a ::before
pseudo elementscrollWidth
is larger than the clientWidth
:
const ellipsify = (elParent) => {
const elInput = elParent.querySelector("input");
const init = () => {
const chars = elInput.value;
const tot = chars.length;
const half = Math.floor(tot / 2);
let i = 0;
elParent.dataset.val = elInput.value;
while (i < half && elParent.scrollWidth > elParent.offsetWidth) {
const ir = Math.max(0, Math.floor((tot - i) / 2)); // index of removal
elParent.dataset.val = [...chars].toSpliced(ir, i, " … ").join("");
i += 2;
}
};
elInput.addEventListener("blur", init);
init();
};
document.querySelectorAll(".input-ellipsis").forEach(ellipsify);
.input-ellipsis {
position: relative;
display: inline-flex;
align-items: center;
>* {
font: inherit;
line-height: 1.3em;
box-sizing: border-box;
}
&::before {
content: attr(data-val);
position: absolute;
line-height: 1.5em;
pointer-events: none;
width: 100%;
color: #000;
white-space: nowrap;
text-indent: 4px;
}
&:has(input:focus)::before {
opacity: 0;
}
input {
appearance: none;
color: transparent;
&:focus {
color: #000;
}
}
}
<span class="input-ellipsis">
<input type="text" placeholder="Enter your text" value="The quick brown fox jumps over the lazy dog." />
</span>
<span class="input-ellipsis">
<input type="text" placeholder="Enter your text" value="No ellipsis needed!" />
</span>
<span class="input-ellipsis">
<input type="text" placeholder="Enter your text" value="" />
</span>
Depending on the expected length of the input value you might want to inverse the logic for efficiency.
With the above, the INPUT's value
never changes and you can submit it to the server without any issues. The trick in the example above is the opacity and text color we use to switch in order to show the ::before
contents or the input value, when focused.
PS: what I would additionally improve (out of scope for this answer) is: if a user focuses the input in the second portion of the text (right of the ellipsis), when the input value "enlarges" - move the caret to match the focused position-in-text.