diff --git a/assets/js/hooks/index.js b/assets/js/hooks/index.js index a75f5d117..01ea9f6df 100644 --- a/assets/js/hooks/index.js +++ b/assets/js/hooks/index.js @@ -12,6 +12,7 @@ import KeyboardControl from "./keyboard_control"; import MarkdownRenderer from "./markdown_renderer"; import ScrollOnUpdate from "./scroll_on_update"; import Session from "./session"; +import TextareaAutosize from "./textarea_autosize"; import Timer from "./timer"; import UserForm from "./user_form"; import VirtualizedLines from "./virtualized_lines"; @@ -31,6 +32,7 @@ export default { MarkdownRenderer, ScrollOnUpdate, Session, + TextareaAutosize, Timer, UserForm, VirtualizedLines, diff --git a/assets/js/hooks/textarea_autosize.js b/assets/js/hooks/textarea_autosize.js new file mode 100644 index 000000000..963cf5c87 --- /dev/null +++ b/assets/js/hooks/textarea_autosize.js @@ -0,0 +1,25 @@ +const BORDER_HEIGHT = 1; + +/** + * A hook that automatically matches textarea height to its content. + */ +const TextareaAutosize = { + mounted() { + this.autosize(); + + this.el.addEventListener("input", (event) => { + this.autosize(); + }); + }, + + updated() { + this.autosize(); + }, + + autosize() { + this.el.style.height = "0px"; + this.el.style.height = `${this.el.scrollHeight + 2 * BORDER_HEIGHT}px`; + }, +}; + +export default TextareaAutosize; diff --git a/lib/livebook_web/live/output/input_component.ex b/lib/livebook_web/live/output/input_component.ex index 4b8709b92..744b32a09 100644 --- a/lib/livebook_web/live/output/input_component.ex +++ b/lib/livebook_web/live/output/input_component.ex @@ -98,9 +98,11 @@ defmodule LivebookWeb.Output.InputComponent do defp input(%{attrs: %{type: :textarea}} = assigns) do ~H"""