Giter Club home page Giter Club logo

stretchy's Introduction

Stretchy

Form element autosizing, the way it should be!

Features

  • Handles multiple types of form controls Textareas? Inputs? Select menus? You name it!
  • Tiny footprint Less than 1.5KB minified and gzipped!
  • Automatically accounts for newly added controls via mutation observers
  • Restrict form controls by a selector …or don’t and autosize all your form controls!
  • Completely standalone no jQuery or other dependencies
  • Plays well with existing HTML/CSS Follows placeholders, styling, min/max-width/height constraints, transitions
  • No JS knowledge required Everything can be configured just via HTML!
  • Works in all modern browsers (v1 even works in old browsers)
  • Written in ESM Available in ESM, CJS, and good ol' globals
  • Works in Shadow DOM Use it in your web components!

Usage

Good ol’ <script> element

This method is optimal if you don't need much control, and would rather avoid writing any JS.

Just include the script anywhere in the page:

<script src="https://stretchy.verou.me/dist/stretchy.iife.min.js" async></script>

If you include Stretchy this way it will run automatically and you don’t need to do anything else (unless you want to customize which elements it applies to).

ESM (v2.0.0+)

This method is ideal if you are including Stretchy as a dependency on a larger project and want to prevent any side effects.

import * as Stretchy from "https://stretchy.verou.me/dist/stretchy.min.js";
Stretchy.init();

CommonJS (v2.0.0+)

A CommonJS build is also available. require("stretchy") should work on Node.

Local files

All three of the above methods can be used with your own local files as well. You can download Stretchy here.

npm works like you’d expect too:

npm install stretchy

Which elements does Stretchy resize?

By default, Stretchy resizes all <textarea>s, <select> menus with no size attribute and <input> elements that are text fields (e.g. with no type attribute, or with one equal to text, tel, email, url).

To limit that set further you can set an additional filter, via a CSS selector. There are two ways to specify a filter: via HTML attributes (if you'd prefer to avoid writing JS) or via JS.

Via HTML attributes:

Use the data-stretchy-filter attribute, on any element. Note that this means you can use the attribute on the <script> element that calls Stretchy itself, in which case you can also shorten its name to data-filter.

For example, to restrict it to elements that either have the foo class or are inside another element that does, you could use data-stretchy-filter=".foo, .foo *" on an element or call Stretchy like this:

<script src="stretchy.min.js" data-filter=".foo, .foo *" async></script>

If you specify the data-stretchy-filter attribute on multiple elements, the last value (in source order) wins. data-filter directly on Stretchy’s <script> element takes priority over any data-stretchy-filter declaration.

Via JS

If you want to avoid modifying the markup, you can use JavaScript instead:

Stretchy.selectors.filter = ".foo, .foo *";

Note that if you are including Stretchy via a <script> element, it will run as soon as the document is ready, which may be before you’ve set a filter. You need to ensure that line runs after Stretchy has loaded (so that the Stretchy object is available) and before the DOM is ready. To avoid this hassle, I'd recommend using attributes to set the filter if you include Stretchy that way, or including Stretchy as a module if you want to customize its settings via JS.

JavaScript API

Stretchy has a spartan API, since in most cases you don’t need to call it at all. Stretchy works via event delegation and detects new elements via mutation observers, so you do not need to call any API methods for adding new elements via scripting (e.g. AJAX).

If needed, these are Stretchy’s API methods:

Property or Method Description
init([root]) Resize controls inside a given element, and monitor for changes. root can be any Node, including Shadow roots.
resize(element) Autosize one element based on its content. Note that this does not set up any event listeners, it just calculates and sets the right dimension (width or height, depending on the type of control) once.
resizeAll([elements | selector, [root]]) Apply Stretchy.resize() to a collection of elements, or all Stretchy is set to apply to, if no argument is provided.
resizes(element) Can Stretchy be used on this particular element? (checks if element is in the DOM, if it's of the right type and if it matches the selector filter provided by data-stretchy-selector, if the attribute is set.
selectors.base CSS selector to tell Stretchy which elements can be resized. Defaults to input, select, textarea. Main use case for modifying this is in case you have a custom element that behaves like these and want Stretchy to stop ignoring it. If you just want to filter which elements Stetchy resizes, use filter below.
selectors.filter CSS selector that elements need to match to be resized.
active Boolean. Set to false to temporarily disable Stretchy globally.`

Browser support

All modern browsers. For details, see .browserslistrc

v1 Browser Support Notes

Stretchy v1 worked in Chrome, FF 3.6, IE9, Opera, Safari, Android & more.

stretchy's People

Contributors

alexa-green avatar ashsearle avatar dpschen avatar hawkrives avatar jonnyburger avatar khaledtouaibia avatar leaverou avatar mathiasbynens avatar mthjn avatar svgeesus avatar yukulele avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

stretchy's Issues

Binding to 'input' and 'change' events too early?

I've come across a race condition this morning whereby typing in a form field before Stretchy has inited results in the field being resized, even if it doesn't match the filter criteria.

My current hunch on this is that we're binding to the 'input' and 'change' events on the document before the plugin has inited, meaning it can receive resize() calls before the filters are in place.

It looks like listener() is checking an active flag, but the flag is always true, even before init() is run, so doesn't really add any protection.

I'd propose that active() should be false, until init() is complete, or that the binding of the input and change events should happen within or after the init() to prevent this race condition.

Any thoughts?

script async + grabbing self script

You are suggesting to use async to load stretchy and it's like "you" are assuming that will act like a single blocking script in the page through the $$('script').pop() logic.

You know that's not how async really work, that might work only if you have only stretchy in the page as async, otherwise that popped script can be pretty much any other script, even some after ;-)

Indeed you have to fallback later on within the init looking for properties and re-searching for the script with the data-stretchy-filter

It feels like there's some unnecessary search when you address the script property and you could just search once the right thing on the init?

Moreover, but it could be a minor (or more rare) issue, some quite modern Firefox is known to have an issue with DOMContentLoaded and async / defer scripts so that it might never fire 'cause the loading state won't be loading but DOMContentLoaded won't execute neither ( the Web is always fun, isn't it? )

This is how I ended up solving it, putting an inline script on my templates that brings document.ready in ... it grants on every device on earth the thing will be executed via document.ready(callback) :D

Of course just dropping that async would work as well.

For others who might read this bug, curious to know more about why async is not really a holy grail for the web: http://webreflection.blogspot.co.uk/2014/02/the-underestimated-problem-about-script.html

Cheers

Set min height

Is there any option to set a min-height to the fields?
Because all my textfields are only 46px high on load (without content), but I want them to be 300px.

When I set min-height to 300px for this field, the height is 398px on load.

Also the selector does not work (all other fields are also changed):

Stretchy.selectors.filter = "#message";
<textarea id="message"/>

Type definitions

I'd like to add type definitions for the library to DefinitelyTyped, but unfortunaltely the active global property is preventing that:

export let active = true;

Since in TypeScript type definition files all exported variables are treated as read-only, and cannot be reassigned. Would it be possbile to convert this to a function? For example:

let active = true;

function setActive(isActive) {
    active = isActive;
}

This way the library could be (more easily) usable in TypeScript projects. You can see my current type definition implementation here.

Bug: incorrect scrollLeft on input in webkits

When you're writing something in an input in webkits, the input gets the scrollLeft equal to 1, so the text becomes clipped until you'd move a cursor.

Here is a gif demonstrating this problem:

stretchy

Crossbrowser inconsistencies with the <select>-element

Some inconsistencies I saw when comparing the <select> examples across browsers (as customized ones are always pain in crossbrowser uses) (in order: Chrome 44.0, FF 39, IE11):

image

image

image

  • The initial state on Chrome looks great, but the texts on the dropdown are nearly unreadble
  • On Firefox, it nearly the opposite: the dropdown looks great (sans the beveled borders) but the default state of the box is clipped
  • IE11 showcases the same text thing than Chrome, but with different color ::hover. The box doesn't scale itself when selecting a value, as measuring the dummy throws an error:
 Unable to get property '0' of undefined or null reference

        else if(type == "select") {
            // Need to use dummy element to measure :(
            var option = document.createElement("_");
            option.textContent = element.selectedOptions[0].textContent; //selectedOptions here is undefined, it doesn't seem to be supported on IE

Otherwise looking great 👍

Loading with 'async' can break filter

Elements get matched by data-filter even though they shouldn't if you load stretchy asynchronously.

Example: http://codepen.io/JonnyBurger/pen/rOEPOV
Same example, but without async: http://codepen.io/JonnyBurger/pen/ZbdwWY here everything is ok.

What happens is the following:

  1. Stretchy gets initialized, has default filter '*'
  2. Elements get added to the page, Stretchy listens to them.
  3. DOMContentLoaded, Stretchy updates to user defined filter, but previous elements are already watched.

I will follow up with a pull request shortly.

Textarea with a padding of 12px adds extra line

I have a textarea with a padding of 12px and I get 2 lines instead of 1, the extra expands with the textarea and is always visible.

This does not happen when I remove the offset in the code (line 60).

Selects with box-sizing:border-box and padding is broken in Firefox.

I discovered a problem with selects in Firefox when there is padding on the select element.

example-select-bug

It seems like the calculations ignore the padding-left and padding-right and sets the width to exactly what the text-width is.

This happens in Firefox on OSX at least, no problems in Chrome but I see kind of the same on Edge In Win10.

ES6-compliant configuration

I am working on a SPA built with Webpack and I want to configure the Stretchy selector with Javascript, as opposed to doing it with the data-filter value. The problem is that, to my understanding, Stretchy is defining a global variable without any control. The only way I have to set the selector is

import "stretchy";
window.onload = function() {
    ...
    Stretchy.selectors.filter = ".my-selector";
    ...
}

Is that good practice? I mean, I would expect to do a named import, something like import * as Stretchy from "stretchy".

Broken in Microsoft Edge

It appears the width of input elements controlled by Stretchy is always set to 0 in MS Edge 38.14393.0.0 on Windows 10.

Exclude / Disable stretchy for some inputs

Everything is working great and as intended, so thanks a lot for this handy JS.

The only thing is that I want to disable Stretchy for some inputs like for example autocomplete inputs as it stretches badly in this case.

thanks

<input>'s don't resize on IE

Yay, yet another IE bug (tested with Microsoft Edge, IE11, IE11 Mobile, most likely affects all of them).

When calculating the placeholder width on stretchy.js#L76

var width = Math.max(element.scrollLeft + offset, element.scrollWidth - element.clientWidth);

the problem is that element.scrollLeft never actually updates on <input>-elements on IE, which results to the inputs being offset wide forever:

image

There's an workaround for Safari above that line, but like I said, I think the value of scrollLeft stays 0 forever no matter what so I think any workarounds using scrollLeft are out of the picture for an IE fix.

The popular[1] workaround[2] is to use <textarea>s with single rows forced instead, but that doesn't really apply to Scretchy as the whole point is to have a variety of autosizing form elements instead of just going "screw it, just use <textarea> for everything" 🔨

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.