Panel one
- ^
+ ^
Panel one content
Panel two
- ^
+ ^
Panel two content
Panel three
- ^
+ ^
Panel three content
diff --git a/packages/web-components/fast-foundation/src/accordion/accordion.template.ts b/packages/web-components/fast-foundation/src/accordion/accordion.template.ts
new file mode 100644
index 00000000000..5e36bd1f344
--- /dev/null
+++ b/packages/web-components/fast-foundation/src/accordion/accordion.template.ts
@@ -0,0 +1,8 @@
+import { html, slotted } from "@microsoft/fast-element";
+import { Accordion } from "./accordion";
+
+export const AccordionTemplate = html
`
+
+
+
+`;
diff --git a/packages/web-components/fast-foundation/src/accordion/accordion.ts b/packages/web-components/fast-foundation/src/accordion/accordion.ts
new file mode 100644
index 00000000000..92d441d98db
--- /dev/null
+++ b/packages/web-components/fast-foundation/src/accordion/accordion.ts
@@ -0,0 +1,131 @@
+import { attr, FASTElement, observable } from "@microsoft/fast-element";
+import {
+ keyCodeArrowDown,
+ keyCodeArrowUp,
+ keyCodeEnd,
+ keyCodeHome,
+ wrapInBounds,
+} from "@microsoft/fast-web-utilities";
+import { AccordionItem } from "./accordion-item";
+
+export enum AccordionExpandMode {
+ single = "single",
+ multi = "multi",
+}
+
+export class Accordion extends FASTElement {
+ @attr({ attribute: "expand-mode" })
+ public expandmode: AccordionExpandMode = AccordionExpandMode.multi;
+
+ @observable
+ public accordionItems: HTMLElement[];
+ public accordionItemsChanged(oldValue, newValue): void {
+ if (this.$fastController.isConnected) {
+ this.removeItemListeners(oldValue);
+ this.accordionIds = this.getItemIds();
+ this.setItems();
+ }
+ }
+
+ private activeid: string;
+ private activeItemIndex: number = 0;
+ private accordionIds: Array;
+
+ private change = (): void => {
+ this.$emit("change");
+ };
+
+ private setItems = (): void => {
+ this.accordionIds = this.getItemIds();
+ this.accordionItems.forEach((item: HTMLElement, index: number) => {
+ if (item instanceof AccordionItem) {
+ item.addEventListener("change", this.activeItemChange);
+ if (this.isSingleExpandMode()) {
+ this.activeItemIndex !== index
+ ? (item.expanded = false)
+ : (item.expanded = true);
+ }
+ }
+ const itemId: string | null = this.accordionIds[index];
+ item.setAttribute(
+ "id",
+ typeof itemId !== "string" ? `accordion-${index + 1}` : itemId
+ );
+ this.activeid = this.accordionIds[this.activeItemIndex] as string;
+ item.addEventListener("keydown", this.handleItemKeyDown);
+ });
+ };
+
+ private resetItems(): void {
+ this.accordionItems.forEach((item: AccordionItem, index: number) => {
+ item.expanded = false;
+ });
+ }
+
+ private removeItemListeners = (oldValue: any): void => {
+ oldValue.forEach((item: HTMLElement, index: number) => {
+ item.removeEventListener("change", this.activeItemChange);
+ item.removeEventListener("keydown", this.handleItemKeyDown);
+ });
+ };
+
+ private activeItemChange = (event): void => {
+ const selectedItem = event.target as HTMLElement;
+ if (this.isSingleExpandMode()) {
+ this.resetItems();
+ event.target.expanded = true;
+ }
+ this.activeid = event.target.getAttribute("id");
+ this.activeItemIndex = Array.from(this.accordionItems).indexOf(selectedItem);
+ this.change();
+ };
+
+ private getItemIds(): Array {
+ return this.accordionItems.map((accordionItem: HTMLElement) => {
+ return accordionItem.getAttribute("id");
+ });
+ }
+
+ private isSingleExpandMode(): boolean {
+ return this.expandmode === AccordionExpandMode.single;
+ }
+
+ private handleItemKeyDown = (event: KeyboardEvent): void => {
+ const keyCode: number = event.keyCode;
+ this.accordionIds = this.getItemIds();
+ switch (keyCode) {
+ case keyCodeArrowUp:
+ event.preventDefault();
+ this.adjust(-1);
+ break;
+ case keyCodeArrowDown:
+ event.preventDefault();
+ this.adjust(1);
+ break;
+ case keyCodeHome:
+ this.activeItemIndex = 0;
+ this.focusItem();
+ break;
+ case keyCodeEnd:
+ this.activeItemIndex = this.accordionItems.length - 1;
+ this.focusItem();
+ break;
+ }
+ };
+
+ private adjust(adjustment: number): void {
+ this.activeItemIndex = wrapInBounds(
+ 0,
+ this.accordionItems.length - 1,
+ this.activeItemIndex + adjustment
+ );
+ this.focusItem();
+ }
+
+ private focusItem(): void {
+ const element: HTMLElement = this.accordionItems[this.activeItemIndex];
+ if (element instanceof AccordionItem) {
+ element.expandbutton.focus();
+ }
+ }
+}
diff --git a/packages/web-components/fast-foundation/src/accordion/index.ts b/packages/web-components/fast-foundation/src/accordion/index.ts
new file mode 100644
index 00000000000..806fb840849
--- /dev/null
+++ b/packages/web-components/fast-foundation/src/accordion/index.ts
@@ -0,0 +1,3 @@
+export * from "./accordion.template";
+export * from "./accordion";
+export * from "./accordion-item";
diff --git a/packages/web-components/fast-foundation/src/index.ts b/packages/web-components/fast-foundation/src/index.ts
index bd0a945a07e..1c625d62657 100644
--- a/packages/web-components/fast-foundation/src/index.ts
+++ b/packages/web-components/fast-foundation/src/index.ts
@@ -1,3 +1,4 @@
+export * from "./accordion/index";
export * from "./anchor/index";
export * from "./badge/index";
export * from "./button/index";
diff --git a/packages/web-components/fast-foundation/src/patterns/start-end.ts b/packages/web-components/fast-foundation/src/patterns/start-end.ts
index 2ee49d818b6..997b3590a0c 100644
--- a/packages/web-components/fast-foundation/src/patterns/start-end.ts
+++ b/packages/web-components/fast-foundation/src/patterns/start-end.ts
@@ -18,7 +18,7 @@ export class StartEnd {
}
export const endTemplate = html`
-
+
`
`;
export const startTemplate = html`
-
+