+ {{#if charCounter}}
+
+
+
+ 0/{{maxLength}}
+
+
+ {{else}}
+
+ {{/if}}
+
Optional helper text goes here
-
diff --git a/packages/components/src/components/text-area/text-area.js b/packages/components/src/components/text-area/text-area.js
new file mode 100644
index 000000000000..9bbc135ee6b7
--- /dev/null
+++ b/packages/components/src/components/text-area/text-area.js
@@ -0,0 +1,74 @@
+/**
+ * Copyright IBM Corp. 2016, 2018
+ *
+ * This source code is licensed under the Apache-2.0 license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+import settings from '../../globals/js/settings';
+import mixin from '../../globals/js/misc/mixin';
+import createComponent from '../../globals/js/mixins/create-component';
+import initComponentBySearch from '../../globals/js/mixins/init-component-by-search';
+import handles from '../../globals/js/mixins/handles';
+import on from '../../globals/js/misc/on';
+
+export default class TextArea extends mixin(
+ createComponent,
+ initComponentBySearch,
+ handles
+) {
+ /**
+ * Text Area.
+ * @extends CreateComponent
+ * @extends InitComponentBySearch
+ * @extends Handles
+ * @param {HTMLElement} element - The textarea element
+ */
+ constructor(element, options) {
+ super(element, options);
+ this.manage(
+ on(this.element, 'input', event => {
+ if (event.target.maxLength < 0) {
+ return;
+ }
+ this._handleInput({ element, length: event.target.value.length });
+ })
+ );
+ }
+
+ /**
+ * Updates the character counter
+ * @param {Object} obj - The elements that can change in the component
+ * @param {HTMLElement} obj.element - The textarea element
+ * @param {HTMLElement} obj.length - The length of the textarea value
+ */
+ _handleInput = ({ element, length }) => {
+ element.querySelector(
+ this.options.selectorCharCounter
+ ).textContent = length;
+ };
+
+ /**
+ * The component options.
+ *
+ * If `options` is specified in the constructor,
+ * {@linkcode TextArea.create .create()},
+ * or {@linkcode TextArea.init .init()},
+ * properties in this object are overriden for the instance being
+ * created and how {@linkcode TextArea.init .init()} works.
+ * @property {string} selectorInit The CSS selector to find textarea UIs.
+ */
+ static get options() {
+ const { prefix } = settings;
+ return {
+ selectorInit: '[data-text-area]',
+ selectorCharCounter: `.${prefix}--text-area--character-counter--length`,
+ };
+ }
+
+ /**
+ * The map associating DOM element and textarea UI instance.
+ * @type {WeakMap}
+ */
+ static components /* #__PURE_CLASS_PROPERTY__ */ = new WeakMap();
+}
diff --git a/packages/components/src/components/text-input/_text-input.scss b/packages/components/src/components/text-input/_text-input.scss
index 9cefb6e41184..fe726bc2c54e 100644
--- a/packages/components/src/components/text-input/_text-input.scss
+++ b/packages/components/src/components/text-input/_text-input.scss
@@ -59,12 +59,41 @@
background-color: $field-02;
}
+ // -----------------
+ // Character counter
+ // -----------------
+ .#{$prefix}--text-input__character-counter-title {
+ display: flex;
+ justify-content: space-between;
+ width: 100%;
+ }
+
+ .#{$prefix}--text-input__character-counter-title
+ + .#{$prefix}--form__helper-text {
+ margin-top: rem(-6px);
+ }
+
+ .#{$prefix}--text-input__character-counter-title .#{$prefix}--label {
+ margin-right: rem(16px);
+ }
+
+ .#{$prefix}--text-input--character-counter {
+ margin-bottom: $carbon--spacing-03;
+ @include type-style('label-01');
+ color: $text-02;
+ }
+
+ .#{$prefix}--text-input--character-counter--disabled {
+ color: $disabled-02;
+ }
+
//-----------------------------
// Disabled & Error icon spacing
//-----------------------------
.#{$prefix}--text-input__field-wrapper {
position: relative;
display: flex;
+ width: 100%;
align-items: center;
.#{$prefix}--text-input__invalid-icon {
diff --git a/packages/components/src/components/text-input/text-input.config.js b/packages/components/src/components/text-input/text-input.config.js
index ffef1f08f482..1d0a318a9377 100644
--- a/packages/components/src/components/text-input/text-input.config.js
+++ b/packages/components/src/components/text-input/text-input.config.js
@@ -30,6 +30,23 @@ module.exports = {
light: true,
},
},
+ {
+ name: 'character-counter',
+ label: 'Text Input with character counter',
+ context: {
+ charCounter: true,
+ maxLength: 100,
+ },
+ },
+ {
+ name: 'character-counter--light',
+ label: 'Text Input with character counter (light)',
+ context: {
+ charCounter: true,
+ maxLength: 100,
+ light: true,
+ },
+ },
{
name: 'password',
label: 'Password Input',
@@ -45,5 +62,24 @@ module.exports = {
password: true,
},
},
+ {
+ name: 'password--character-counter',
+ label: 'Password Input with character counter',
+ context: {
+ charCounter: true,
+ maxLength: 100,
+ password: true,
+ },
+ },
+ {
+ name: 'password--light--character-counter',
+ label: 'Password Input with character counter (Light)',
+ context: {
+ charCounter: true,
+ maxLength: 100,
+ light: true,
+ password: true,
+ },
+ },
],
};
diff --git a/packages/components/src/components/text-input/text-input.hbs b/packages/components/src/components/text-input/text-input.hbs
index 9b4fe9b1dcba..c1793824435f 100644
--- a/packages/components/src/components/text-input/text-input.hbs
+++ b/packages/components/src/components/text-input/text-input.hbs
@@ -5,17 +5,29 @@
LICENSE file in the root directory of this source tree.
-->
-
+
-
-
+
-
+
+ {{#if charCounter}}
+
+
+
+ 0/{{maxLength}}
+
+
+ {{else}}
+ {{/if}}
Optional helper text goes here
{{#unless password}}
+ class="{{prefix}}--text-input{{#if light}} {{prefix}}--text-input--light{{/if}}" placeholder="Placeholder text"
+ {{#if charCounter}} maxlength="{{maxLength}}" {{/if}}>
{{else}}
+ placeholder="Placeholder text" {{#if charCounter}} maxlength="{{maxLength}}" {{/if}}
+ data-toggle-password-visibility>
-
+ {{#if charCounter}}
+
+
+
+ 0/{{maxLength}}
+
+
+ {{else}}
+ {{/if}}
Optional helper text here; if message is more than one line text should wrap (~100 character count maximum)
{{#unless password}}
+ class="{{prefix}}--text-input{{#if light}} {{prefix}}--text-input--light{{/if}}" placeholder="Placeholder text"
+ {{#if charCounter}} maxlength="{{maxLength}}" {{/if}}>
{{else}}
+ placeholder="Placeholder text" {{#if charCounter}} maxlength="{{maxLength}}" {{/if}}
+ data-toggle-password-visibility>
-
+
+ {{#if charCounter}}
+
+
+
+ 0/{{maxLength}}
+
+
+ {{else}}
+ {{/if}}
Optional helper text goes here
@@ -111,11 +168,12 @@
{{#unless password}}
+ {{#if charCounter}} maxlength="{{maxLength}}" {{/if}} disabled>
{{else}}
+ placeholder="Placeholder text" {{#if charCounter}} maxlength="{{maxLength}}" {{/if}}
+ data-toggle-password-visibility disabled>