NuoNuo LeRobot
NuoNuo LeRobot

Reputation: 392

How to make an expandable input form for chat

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 !

Upvotes: 8

Views: 4620

Answers (2)

Jan Turoň
Jan Turoň

Reputation: 32914

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();
  }
}

Upvotes: 1

Vahid
Vahid

Reputation: 7561

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"

Upvotes: 8

Related Questions