8

I've searched all over for a way to expand a text input form vertically like they do on modern chat app.

Everyone says that we should use textarea as the form input doesn't allow multi line but slack and spectrum are using forms... (discord use text-area though)

I would like to start with one line, and as user enter line break (shift + enter) the input expand to the top.

.chat-footer {
  display: grid;
  grid-template-rows: 90vh max-content;
  height: 100%;
  background-color: var(--color-i-bg);
  grid-area: i;
  border-top: 1px solid #ddd;
  border-top: var(--color-i-border-top);
  padding-bottom: 1rem;
}
.chat-footer__form {
  align-self: end;
  display: grid;
  grid-row: 2 / 3;
  grid-template-columns: 1fr max-content;
  width: 100%;
  height: 100%;
  vertical-align: middle;
  white-space: normal;
  background: none;
  line-height: 1;
}
.chat-footer__form::placeholder {
  color: lightgrey;
  font-size: 1em;
}
.chat-footer__form-container-input {
  grid-column: 1/2;
}
.chat-footer__form-container-btn {
  grid-column: 2/3;
}
.chat-footer__form-input {
  width: 100%;
  height: 100%;
}
.chat-footer__form * > button {
  background-color: inherit;
  border: 0;
  line-height: normal;
}
.chat-footer__form * > button:hover {
  cursor: pointer;
}
.chat-footer__form * > button:focus, .chat-footer__form * > button:active {
  outline: 0;
}
 <div class="chat-footer">
        <form class="chat-footer__form" role="form">
            <div class="chat-footer__form-container-input">
                <input type="text" class="chat-footer__form-input" placeholder="New message">
            </div>
            <div class="chat-footer__form-container-btn">
                <button class="chat-footer__form-btn" id="form-attach">Attach</button>
                <button class="chat-footer__form-btn" id="form-smiley">Smiley</button>
            </div>
        </form>
    </div>

I'm not against using text-area if it's a better solution.

EDIT---

Finaly I used the solution with contenteditable="true" with overflow:auto; on my main container, and used the this for the placeholder:

&[placeholder]:empty:not(:focus):before {
    content: attr(placeholder);
}

This did the trick. Thanks all for your answers !

NuoNuo LeRobot
  • 370
  • 3
  • 16
  • A [ – KIKO Software May 11 '19 at 07:35
  • possible duplicate of: https://stackoverflow.com/a/54383032/8620333 – Temani Afif May 11 '19 at 09:49
  • If you got the solution please write it as an Answer below. The solution does not belong as part of your question (which hopefully is obvious if you think about it!). You are allowed and encouraged to answer your own questions – ADyson May 11 '19 at 17:05
  • Finaly I used the solution with contenteditable="true" with overflow:auto; on my main container, and used the this for the placeholder: &[placeholder]:empty:not(:focus):before { content: attr(placeholder); } This did the trick. Thanks all for your answers ! – NuoNuo LeRobot Jun 12 '19 at 11:34

2 Answers2

8

You can have a div (no input and no textarea) and use contenteditable="true" attribute:

<div contenteditable="true"></div>

Now when users click on the div, they can write things! exactly like an input. So you just need to listen for the events of this div and for example when user presses shift+enter add a <br> tag or create some paragraphs.

I checked slack input and they use the same technique. there are also some other attributes which you may want to use:

 autocomplete="off" autocorrect="off" spellcheck="true" aria-expanded="false" aria-autocomplete="list" aria-multiline="true" aria-label="Message" dir="auto" contenteditable="true" role="textbox"
Vahid
  • 6,639
  • 5
  • 37
  • 61
  • Oh yeah right this seems interesting solution ! I'll investigate this way, thanks a lot. – NuoNuo LeRobot May 11 '19 at 08:12
  • @NuoNuoLeRobot Good to hear that. I've once created a really simple WYSIWYG editor using this technique. Feel free to ask questions. – Vahid May 11 '19 at 08:43
1

To expand the input from bottom up:

.chat-footer__form-container-input {
  position: relative;
}
.chat-footer__form-input {
  position: absolute;
  bottom: 0;
}

To grow on shift+Enter, I would recommend textarea with JS input handler:

<textarea onkeypress="handleInput(event)" class="chat-footer__form-input" placeholder="New message"></textarea>

Set its height in absolute units of one line:

.chat-footer__form-input {
  width: 100%;
  height: 20px;
}

And set the script with the shift+Enter behavior (only Enter submits the form):

function handleInput(e) {
  if(e.key=="Enter") {
    if(e.shiftKey) e.target.style.height = e.target.offsetHeight+20+"px";
    else e.target.form.submit();
  }
}
Jan Turoň
  • 31,451
  • 23
  • 125
  • 169