diff --git a/field/internal/field.ts b/field/internal/field.ts
index efc8bdc6b2..1ef45b695a 100644
--- a/field/internal/field.ts
+++ b/field/internal/field.ts
@@ -120,6 +120,8 @@ export class Field extends LitElement implements SurfacePositionTarget {
${this.renderBackground?.()}
+ ${this.renderIndicator?.()}
+ ${outline}
@@ -137,8 +139,6 @@ export class Field extends LitElement implements SurfacePositionTarget {
- ${outline}
- ${this.renderIndicator?.()}
${this.renderSupportingText()}
diff --git a/textfield/demo/demo.ts b/textfield/demo/demo.ts
index 818bb6ed69..0ee83bf5fe 100644
--- a/textfield/demo/demo.ts
+++ b/textfield/demo/demo.ts
@@ -8,28 +8,19 @@ import './index.js';
import './material-collection.js';
import {KnobTypesToKnobs, MaterialCollection, materialInitsToStoryInits, setUpDemo} from './material-collection.js';
-import {boolInput, Knob, numberInput, textInput} from './index.js';
+import {boolInput, Knob, textInput} from './index.js';
import {stories, StoryKnobs} from './stories.js';
const collection =
new MaterialCollection>('Textfield', [
new Knob('label', {ui: textInput(), defaultValue: 'Label'}),
- new Knob('textarea', {ui: boolInput(), defaultValue: false}),
+ new Knob('placeholder', {ui: textInput(), defaultValue: ''}),
new Knob('disabled', {ui: boolInput(), defaultValue: false}),
- new Knob('required', {ui: boolInput(), defaultValue: false}),
new Knob('prefixText', {ui: textInput(), defaultValue: ''}),
new Knob('suffixText', {ui: textInput(), defaultValue: ''}),
new Knob(
'supportingText', {ui: textInput(), defaultValue: 'Supporting text'}),
- new Knob('minLength', {ui: numberInput(), defaultValue: -1}),
- new Knob('maxLength', {ui: numberInput(), defaultValue: -1}),
- new Knob('min', {ui: textInput(), defaultValue: ''}),
- new Knob('max', {ui: textInput(), defaultValue: ''}),
- new Knob('step', {ui: textInput(), defaultValue: ''}),
- new Knob('pattern', {ui: textInput(), defaultValue: ''}),
- new Knob('leading icon', {ui: boolInput(), defaultValue: false}),
- new Knob('trailing icon', {ui: boolInput(), defaultValue: false}),
]);
collection.addStories(...materialInitsToStoryInits(stories));
diff --git a/textfield/demo/stories.ts b/textfield/demo/stories.ts
index 6b4a18d78e..5414bbe3e7 100644
--- a/textfield/demo/stories.ts
+++ b/textfield/demo/stories.ts
@@ -4,6 +4,8 @@
* SPDX-License-Identifier: Apache-2.0
*/
+import '@material/web/button/outlined-button.js';
+import '@material/web/button/text-button.js';
import '@material/web/icon/icon.js';
import '@material/web/iconbutton/icon-button.js';
import '@material/web/textfield/filled-text-field.js';
@@ -16,24 +18,27 @@ import {css, html, nothing} from 'lit';
/** Knob types for Textfield stories. */
export interface StoryKnobs {
label: string;
- textarea: boolean;
+ placeholder: string;
disabled: boolean;
- required: boolean;
prefixText: string;
suffixText: string;
supportingText: string;
- minLength: number;
- maxLength: number;
- min: string;
- max: string;
- step: string;
- pattern: string;
- 'leading icon': boolean;
- 'trailing icon': boolean;
}
// Set min-height for resizable textareas
const styles = css`
+ .row {
+ align-items: flex-start;
+ display: flex;
+ flex-wrap: wrap;
+ gap: 16px;
+ }
+
+ md-filled-text-field,
+ md-outlined-text-field {
+ width: 200px;
+ }
+
[type=textarea] {
min-height: 56px;
}
@@ -43,68 +48,207 @@ const styles = css`
}
`;
-const filled: MaterialStoryInit = {
- name: '',
+const textfields: MaterialStoryInit = {
+ name: 'Text fields',
+ styles,
+ render(knobs) {
+ return html`
+
+
+
+
+
+ `;
+ }
+};
+
+const textareas: MaterialStoryInit = {
+ name: 'Text areas',
+ styles,
+ render(knobs) {
+ return html`
+
+
+
+
+
+ `;
+ }
+};
+
+const icons: MaterialStoryInit = {
+ name: 'Icons',
styles,
render(knobs) {
return html`
-
- ${knobs['leading icon'] ? LEADING_ICON : nothing}
- ${knobs['trailing icon'] ? TRAILING_ICON : nothing}
-
+
+
+ search
+
+ clear
+
+
+
+
+ search
+
+ clear
+
+
+
`;
}
};
-const outlined: MaterialStoryInit = {
- name: '',
+const validation: MaterialStoryInit = {
+ name: 'Validation',
styles,
render(knobs) {
return html`
-
- ${knobs['leading icon'] ? LEADING_ICON : nothing}
- ${knobs['trailing icon'] ? TRAILING_ICON : nothing}
-
+
+
+
+
+
+
+
+
+
+ `;
+ }
+};
+
+const forms: MaterialStoryInit = {
+ name: 'Forms',
+ styles: [
+ styles,
+ css`
+ .buttons {
+ justify-content: flex-end;
+ padding: 16px;
+ }
+ `,
+ ],
+ render(knobs) {
+ return html`
+
`;
}
};
-const LEADING_ICON = html`search`;
-const TRAILING_ICON =
- html`event`;
function reportValidity(event: Event) {
(event.target as MdFilledTextField).reportValidity();
}
+function clearInput(event: Event) {
+ const iconButton = event.target as HTMLElement;
+ const textField = iconButton.parentElement as MdFilledTextField;
+ iconButton.blur();
+ textField.value = '';
+ textField.focus();
+}
+
+function alertValues(event: SubmitEvent) {
+ event.preventDefault();
+ const data = new FormData(event.target as HTMLFormElement);
+ const first = data.get('first-name') || '';
+ const last = data.get('last-name') || '';
+ alert(`First name: ${first}, Last name: ${last}`);
+}
+
/** Textfield stories. */
-export const stories = [filled, outlined];
+export const stories = [textfields, textareas, icons, validation, forms];
diff --git a/textfield/internal/_input.scss b/textfield/internal/_input.scss
index 4caf48eb18..cd638b6cef 100644
--- a/textfield/internal/_input.scss
+++ b/textfield/internal/_input.scss
@@ -65,6 +65,7 @@
.prefix,
.suffix {
+ text-wrap: nowrap;
width: min-content;
}