Expanding text input fields?

Here’s an example based on the clever solution mentioned by @chriddyp :smiley:

autoresizing-inputs

And here’s the code

app.py

from dash import Dash, html, dcc, clientside_callback, Output, Input


app = Dash(__name__)
app.layout = html.Div(
    [
        html.Label(
            [
                html.Span("Name: "),
                dcc.Input(id="name_input", size="4", placeholder="John")
            ],
            className="input-sizer",
        ),
        html.Label(
            [
                html.Span("Text: "),
                dcc.Textarea(rows=1, id="text_input", placeholder="Hello World!")
            ],
            className="input-sizer stacked",
        ),
    ],
    style={"display": "flex", "flexDirection": "column", "alignItems": "start"}
)


for element_id in ["name_input", "text_input"]:
    clientside_callback(
        """function(id, value) {
            document.getElementById(id).parentNode.dataset.value = value
            return window.dash_clientside.no_update
        }""",
        Output(element_id, "className"),
        [Input(element_id, "id"), Input(element_id, "value")]
    )


if __name__ == "__main__":
    app.run_server(debug=True)

assets/style.css

*,
*::before,
*::after {
  box-sizing: border-box;
}

.input-sizer {
  display: inline-grid;
  vertical-align: top;
  align-items: center;
  position: relative;
  border: solid 1px;
  padding: 0.25em 0.5em;
  margin: 5px;
  box-shadow: 4px 4px 0px #000;
}

.input-sizer.stacked {
  padding: 0.5em;
  align-items: stretch;
}

.input-sizer.stacked::after,
.input-sizer.stacked input,
.input-sizer.stacked textarea {
  grid-area: 2 / 1;
}

.input-sizer::after,
.input-sizer input,
.input-sizer textarea {
  width: auto;
  min-width: 1em;
  grid-area: 1 / 2;
  font: inherit;
  padding: 0.25em;
  margin: 0;
  resize: none;
  background: none;
  appearance: none;
  border: none;
}

.input-sizer textarea {
  overflow: hidden;
}

.input-sizer::after {
  content: attr(data-value) " ";
  visibility: hidden;
  white-space: pre-wrap;
}

.input-sizer:focus-within {
  outline: solid 1px blue;
  box-shadow: 4px 4px 0px blue;
}

.input-sizer:focus-within > span {
  color: blue;
}

.input-sizer:focus-within textarea:focus,
.input-sizer:focus-within input:focus {
  outline: none;
}

.input-sizer span {
  padding: 0.25em;
}

.input-sizer > span {
  text-transform: uppercase;
  font-size: 0.8em;
  font-weight: bold;
  text-shadow: 2px 2px 0 rgba(0, 0, 0, 0.15);
}

5 Likes