diff --git a/src/demo-app/chips/chips-demo.html b/src/demo-app/chips/chips-demo.html
new file mode 100644
index 000000000000..6e862c6095c7
--- /dev/null
+++ b/src/demo-app/chips/chips-demo.html
@@ -0,0 +1,11 @@
+
+
+ Static Chips
+
+
+ Chip 1
+ Chip 2
+ Chip 3
+
+
+
\ No newline at end of file
diff --git a/src/demo-app/chips/chips-demo.scss b/src/demo-app/chips/chips-demo.scss
new file mode 100644
index 000000000000..996d6cfd641f
--- /dev/null
+++ b/src/demo-app/chips/chips-demo.scss
@@ -0,0 +1,2 @@
+.chips-demo {
+}
\ No newline at end of file
diff --git a/src/demo-app/chips/chips-demo.ts b/src/demo-app/chips/chips-demo.ts
new file mode 100644
index 000000000000..f616fd10204e
--- /dev/null
+++ b/src/demo-app/chips/chips-demo.ts
@@ -0,0 +1,57 @@
+import {Component} from '@angular/core';
+
+export interface Person {
+ name: string;
+}
+
+@Component({
+ moduleId: module.id,
+ selector: 'chips-demo',
+ templateUrl: 'chips-demo.html',
+ styleUrls: ['chips-demo.scss']
+})
+export class ChipsDemo {
+ people:Person[] = [
+ { name: 'Kara' },
+ { name: 'Jeremy' },
+ { name: 'Topher' },
+ { name: 'Elad' },
+ { name: 'Kristiyan' },
+ { name: 'Paul' }
+ ];
+ favorites:Person[] = [];
+
+ alert(message:string): void {
+ alert(message);
+ }
+
+ add(input:HTMLInputElement):void {
+ if (input.value && input.value.trim() != '') {
+ this.people.push({ name: input.value.trim() });
+ input.value = '';
+ }
+ }
+
+ remove(person:Person): void {
+ var index = this.people.indexOf(person);
+
+ if (index > -1 && index < this.people.length) {
+ this.people.splice(index, 1);
+ }
+
+ // We should unfavorite them if they are no longer a contributor
+ this.unfavorite(person);
+ }
+
+ favorite(person:Person): void {
+ this.favorites.push(person);
+ }
+
+ unfavorite(person:Person): void {
+ var index = this.favorites.indexOf(person);
+
+ if (index > -1 && index < this.favorites.length) {
+ this.favorites.splice(index, 1);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/demo-app/demo-app-module.ts b/src/demo-app/demo-app-module.ts
index 048530e046fe..74191dd26cf0 100644
--- a/src/demo-app/demo-app-module.ts
+++ b/src/demo-app/demo-app-module.ts
@@ -13,6 +13,7 @@ import {IconDemo} from './icon/icon-demo';
import {GesturesDemo} from './gestures/gestures-demo';
import {InputDemo} from './input/input-demo';
import {CardDemo} from './card/card-demo';
+import {ChipsDemo} from './chips/chips-demo';
import {RadioDemo} from './radio/radio-demo';
import {ButtonToggleDemo} from './button-toggle/button-toggle-demo';
import {ProgressCircleDemo} from './progress-circle/progress-circle-demo';
@@ -48,6 +49,7 @@ import {TabsDemo, SunnyTabContent, RainyTabContent, FoggyTabContent} from './tab
ButtonDemo,
ButtonToggleDemo,
CardDemo,
+ ChipsDemo,
CheckboxDemo,
DemoApp,
DialogDemo,
diff --git a/src/demo-app/demo-app/demo-app.ts b/src/demo-app/demo-app/demo-app.ts
index 5a10843543af..c13da3e1886a 100644
--- a/src/demo-app/demo-app/demo-app.ts
+++ b/src/demo-app/demo-app/demo-app.ts
@@ -23,6 +23,7 @@ export class DemoApp {
{name: 'Button', route: 'button'},
{name: 'Button Toggle', route: 'button-toggle'},
{name: 'Card', route: 'card'},
+ {name: 'Chips', route: 'chips'},
{name: 'Checkbox', route: 'checkbox'},
{name: 'Dialog', route: 'dialog'},
{name: 'Gestures', route: 'gestures'},
diff --git a/src/demo-app/demo-app/routes.ts b/src/demo-app/demo-app/routes.ts
index 68ec614443db..c9c36d5a6561 100644
--- a/src/demo-app/demo-app/routes.ts
+++ b/src/demo-app/demo-app/routes.ts
@@ -22,6 +22,7 @@ import {SlideToggleDemo} from '../slide-toggle/slide-toggle-demo';
import {SliderDemo} from '../slider/slider-demo';
import {RadioDemo} from '../radio/radio-demo';
import {CardDemo} from '../card/card-demo';
+import {ChipsDemo} from '../chips/chips-demo';
import {MenuDemo} from '../menu/menu-demo';
import {RippleDemo} from '../ripple/ripple-demo';
import {DialogDemo} from '../dialog/dialog-demo';
@@ -33,6 +34,7 @@ export const DEMO_APP_ROUTES: Routes = [
{path: '', component: Home},
{path: 'button', component: ButtonDemo},
{path: 'card', component: CardDemo},
+ {path: 'chips', component: ChipsDemo},
{path: 'radio', component: RadioDemo},
{path: 'select', component: SelectDemo},
{path: 'sidenav', component: SidenavDemo},
diff --git a/src/lib/chips/README.md b/src/lib/chips/README.md
new file mode 100644
index 000000000000..8cad19fae5ff
--- /dev/null
+++ b/src/lib/chips/README.md
@@ -0,0 +1,7 @@
+# md-chips
+
+`md-chips` provides a horizontal display of (optionally) selectable, addable, and removable,
+items and an input to create additional ones (again; optional). You can read more about chips
+in the [Material Design spec](https://material.google.com/components/chips.html).
+
+This is a placeholder README for the eventual chips component.
diff --git a/src/lib/chips/chip.ts b/src/lib/chips/chip.ts
new file mode 100644
index 000000000000..ba58796f37cd
--- /dev/null
+++ b/src/lib/chips/chip.ts
@@ -0,0 +1,26 @@
+import {
+ Component,
+ ElementRef,
+ Renderer
+} from '@angular/core';
+
+@Component(MdChip.COMPONENT_CONFIG)
+export class MdChip {
+
+ static COMPONENT_CONFIG:Component = {
+ selector: 'md-chip, [md-chip]',
+ template: ``,
+ host: {
+ // Properties
+ 'tabindex': '-1',
+ 'role': 'option'
+ }
+ };
+
+ constructor(protected _renderer: Renderer, protected _elementRef: ElementRef) {
+ }
+
+ ngAfterContentInit(): void {
+ this._elementRef.nativeElement.classList.add('md-chip');
+ }
+}
diff --git a/src/lib/chips/chips.scss b/src/lib/chips/chips.scss
new file mode 100644
index 000000000000..9bd8922e523e
--- /dev/null
+++ b/src/lib/chips/chips.scss
@@ -0,0 +1,18 @@
+$md-chip-vertical-padding: 8px;
+$md-chip-horizontal-padding: 12px;
+
+.md-chips {
+ padding: $md-chip-horizontal-padding;
+}
+
+.md-chip {
+ display: inline-block;
+ padding: $md-chip-vertical-padding $md-chip-horizontal-padding
+ $md-chip-vertical-padding $md-chip-horizontal-padding;
+ border-radius: $md-chip-horizontal-padding * 2;
+
+ background-color: #E0E0E0;
+ color: rgba(0, 0, 0, 0.87);
+ font-size: 13px;
+ line-height: 16px;
+}
diff --git a/src/lib/chips/chips.ts b/src/lib/chips/chips.ts
new file mode 100644
index 000000000000..271b50f4ff3c
--- /dev/null
+++ b/src/lib/chips/chips.ts
@@ -0,0 +1,55 @@
+import {
+ ChangeDetectionStrategy,
+ Component,
+ ContentChildren,
+ ElementRef,
+ ModuleWithProviders,
+ NgModule,
+ QueryList,
+ ViewEncapsulation
+} from '@angular/core';
+
+import {MdChip} from './chip';
+
+@Component(MdChips.COMPONENT_CONFIG)
+export class MdChips {
+
+ static COMPONENT_CONFIG: Component = {
+ moduleId: module.id,
+ selector: 'md-chips',
+ template: ``,
+ host: {
+ // Properties
+ 'tabindex': '0',
+ 'role': 'listbox',
+ },
+ queries: {
+ items: new ContentChildren(MdChip)
+ },
+ styleUrls: ['chips.css'],
+ encapsulation: ViewEncapsulation.None,
+ changeDetection: ChangeDetectionStrategy.OnPush
+ };
+
+ protected items: QueryList;
+
+ constructor(private _elementRef: ElementRef) {}
+
+ ngAfterContentInit(): void {
+ this._elementRef.nativeElement.classList.add('md-chips');
+ }
+}
+
+@NgModule({
+ imports: [],
+ exports: [MdChips, MdChip],
+ declarations: [MdChips, MdChip]
+})
+export class MdChipsModule {
+ static forRoot(): ModuleWithProviders {
+ return {
+ ngModule: MdChipsModule,
+ providers: []
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/lib/chips/index.ts b/src/lib/chips/index.ts
new file mode 100644
index 000000000000..7861dd3a337b
--- /dev/null
+++ b/src/lib/chips/index.ts
@@ -0,0 +1,2 @@
+export * from './chips';
+export * from './chip';
diff --git a/src/lib/core/a11y/list-key-manager.ts b/src/lib/core/a11y/list-key-manager.ts
index 8e447ff0c327..c132dc714ac9 100644
--- a/src/lib/core/a11y/list-key-manager.ts
+++ b/src/lib/core/a11y/list-key-manager.ts
@@ -32,10 +32,18 @@ export class ListKeyManager {
return this;
}
- /** Sets the focus of the list to the item at the index specified. */
- setFocus(index: number): void {
+ /**
+ * Sets the focus of the list to the item at the index specified.
+ *
+ * @param index The index of the item to be focused.
+ * @param focusElement Whether or not to focus the element as well. Defaults to `true`.
+ */
+ setFocus(index: number, focusElement: boolean = true): void {
this._focusedItemIndex = index;
- this._items.toArray()[index].focus();
+
+ if (focusElement) {
+ this._items.toArray()[index].focus();
+ }
}
/** Sets the focus properly depending on the key event passed in. */
@@ -43,15 +51,19 @@ export class ListKeyManager {
switch (event.keyCode) {
case DOWN_ARROW:
this.focusNextItem();
+ event.preventDefault();
break;
case UP_ARROW:
this.focusPreviousItem();
+ event.preventDefault();
break;
case HOME:
this.focusFirstItem();
+ event.preventDefault();
break;
case END:
this.focusLastItem();
+ event.preventDefault();
break;
case TAB:
this._tabOut.next(null);
diff --git a/src/lib/core/keyboard/keycodes.ts b/src/lib/core/keyboard/keycodes.ts
index 6204987a0e8a..ab287296e9c8 100644
--- a/src/lib/core/keyboard/keycodes.ts
+++ b/src/lib/core/keyboard/keycodes.ts
@@ -18,3 +18,6 @@ export const END = 35;
export const ENTER = 13;
export const SPACE = 32;
export const TAB = 9;
+
+export const BACKSPACE = 8;
+export const DELETE = 46;
diff --git a/src/lib/index.ts b/src/lib/index.ts
index e242a9fc8777..7202a6b57f55 100644
--- a/src/lib/index.ts
+++ b/src/lib/index.ts
@@ -4,6 +4,7 @@ export * from './module';
export * from './button/index';
export * from './button-toggle/index';
export * from './card/index';
+export * from './chips/index';
export * from './checkbox/index';
export * from './dialog/index';
export * from './grid-list/index';
diff --git a/src/lib/module.ts b/src/lib/module.ts
index 754226b7f0c6..1f3ebbe62610 100644
--- a/src/lib/module.ts
+++ b/src/lib/module.ts
@@ -20,6 +20,7 @@ import {MdSidenavModule} from './sidenav/index';
import {MdListModule} from './list/index';
import {MdGridListModule} from './grid-list/index';
import {MdCardModule} from './card/index';
+import {MdChipsModule} from './chips/index';
import {MdIconModule} from './icon/index';
import {MdProgressCircleModule} from './progress-circle/index';
import {MdProgressBarModule} from './progress-bar/index';
@@ -36,6 +37,7 @@ const MATERIAL_MODULES = [
MdButtonModule,
MdButtonToggleModule,
MdCardModule,
+ MdChipsModule,
MdCheckboxModule,
MdDialogModule,
MdGridListModule,
@@ -66,6 +68,7 @@ const MATERIAL_MODULES = [
imports: [
MdButtonModule.forRoot(),
MdCardModule.forRoot(),
+ MdChipsModule.forRoot(),
MdCheckboxModule.forRoot(),
MdGridListModule.forRoot(),
MdInputModule.forRoot(),