diff --git a/step2-03/README.md b/step2-03/README.md
index 430fbea..fdf3b45 100644
--- a/step2-03/README.md
+++ b/step2-03/README.md
@@ -1,9 +1,81 @@
-# Step 2.2
+# Step 2.3
-Integrates Fabric
+Theming and Styling with UI Fabric. In this section, we will illustrate how to utilize some of the built-in theming and styling features right inside UI Fabric component library. UI Fabric exposes its own css-in-js library called `mergeStyles` that is very performant compared with other similar libraries.
-Learn about Basic Components
+# Exercises
-- Stack
-- Text
-- Show case some components
+## Themes - Using Predefined Theme
+
+Apply some included and predefined themes from the UI Fabric package inside the `/step2-03/exercise/src/components/TodoApp.tsx`. Do this by replacing:
+
+```ts
+import { FluentCustomizations } from '@uifabric/fluent-theme';
+```
+
+with:
+
+```ts
+import { TeamsCustomizations } from '@uifabric/theme-samples';
+```
+
+## Themes - Using Predefined Theme
+
+Create your own theme and apply the color here: https://developer.microsoft.com/en-us/fabric#/styles/themegenerator
+
+```ts
+import { loadTheme } from 'office-ui-fabric-react';
+
+loadTheme({
+ palette: {
+ themePrimary: '#0078d4',
+ themeLighterAlt: '#eff6fc',
+ themeLighter: '#deecf9',
+ themeLight: '#c7e0f4',
+ themeTertiary: '#71afe5',
+ themeSecondary: '#2b88d8',
+ themeDarkAlt: '#106ebe',
+ themeDark: '#005a9e',
+ themeDarker: '#004578',
+ neutralLighterAlt: '#f8f8f8',
+ neutralLighter: '#f4f4f4',
+ neutralLight: '#eaeaea',
+ neutralQuaternaryAlt: '#dadada',
+ neutralQuaternary: '#d0d0d0',
+ neutralTertiaryAlt: '#c8c8c8',
+ neutralTertiary: '#c2c2c2',
+ neutralSecondary: '#858585',
+ neutralPrimaryAlt: '#4b4b4b',
+ neutralPrimary: '#333333',
+ neutralDark: '#272727',
+ black: '#1d1d1d',
+ white: '#ffffff'
+ }
+});
+```
+
+1. Delete the `Customizer` component
+
+2. Paste in this code in the `TodoApp.tsx` before the `TodoApp` component definition
+
+3. Play around with the values and use intellisense to discover the `ITheme` type within VS Code
+
+## CSS in JS with MergeStyles
+
+The styling library name is glamorous nor does it bring about emotion, but it is very quick and lightweight. `MergeStyles` turns CSS Rules into CSS class names to be applied to the components.
+
+1. Try applying a merged style `className` as a prop inside any component that you would find.
+
+```tsx
+import { mergeStyles } from 'office-ui-fabric-react';
+
+const className = mergeStyles({
+ backgroundColor: 'red',
+ selectors: {
+ ':hover': {
+ backgroundColor: 'blue'
+ }
+ }
+});
+```
+
+2. Try to give a few components extra padding
diff --git a/step2-03/index.html b/step2-03/demo/index.html
similarity index 100%
rename from step2-03/index.html
rename to step2-03/demo/index.html
diff --git a/step2-03/src/components/TodoApp.tsx b/step2-03/demo/src/components/TodoApp.tsx
similarity index 100%
rename from step2-03/src/components/TodoApp.tsx
rename to step2-03/demo/src/components/TodoApp.tsx
diff --git a/step2-03/src/components/TodoFooter.tsx b/step2-03/demo/src/components/TodoFooter.tsx
similarity index 100%
rename from step2-03/src/components/TodoFooter.tsx
rename to step2-03/demo/src/components/TodoFooter.tsx
diff --git a/step2-03/src/components/TodoHeader.tsx b/step2-03/demo/src/components/TodoHeader.tsx
similarity index 100%
rename from step2-03/src/components/TodoHeader.tsx
rename to step2-03/demo/src/components/TodoHeader.tsx
diff --git a/step2-03/src/components/TodoList.tsx b/step2-03/demo/src/components/TodoList.tsx
similarity index 100%
rename from step2-03/src/components/TodoList.tsx
rename to step2-03/demo/src/components/TodoList.tsx
diff --git a/step2-03/src/components/TodoListItem.tsx b/step2-03/demo/src/components/TodoListItem.tsx
similarity index 100%
rename from step2-03/src/components/TodoListItem.tsx
rename to step2-03/demo/src/components/TodoListItem.tsx
diff --git a/step2-03/src/index.tsx b/step2-03/demo/src/index.tsx
similarity index 100%
rename from step2-03/src/index.tsx
rename to step2-03/demo/src/index.tsx
diff --git a/step2-03/src/store/index.ts b/step2-03/demo/src/store/index.ts
similarity index 100%
rename from step2-03/src/store/index.ts
rename to step2-03/demo/src/store/index.ts
diff --git a/step2-03/exercise/index.html b/step2-03/exercise/index.html
new file mode 100644
index 0000000..454cef5
--- /dev/null
+++ b/step2-03/exercise/index.html
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/step2-03/exercise/src/components/TodoApp.tsx b/step2-03/exercise/src/components/TodoApp.tsx
new file mode 100644
index 0000000..6699bbd
--- /dev/null
+++ b/step2-03/exercise/src/components/TodoApp.tsx
@@ -0,0 +1,97 @@
+import React from 'react';
+import { Stack, Customizer, mergeStyles, getTheme } from 'office-ui-fabric-react';
+import { TodoFooter } from './TodoFooter';
+import { TodoHeader } from './TodoHeader';
+import { TodoList } from './TodoList';
+import { Store } from '../store';
+
+// TODO: Change me to another theme!
+import { AzureCustomizationsLight } from '@uifabric/azure-themes';
+
+let index = 0;
+
+const className = mergeStyles({
+ padding: 25,
+ ...getTheme().effects.elevation4
+});
+
+export class TodoApp extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ todos: {},
+ filter: 'all'
+ };
+ }
+ render() {
+ const { filter, todos } = this.state;
+ return (
+
+
+
+
+
+
+
+
+
+ );
+ }
+
+ private _addTodo = label => {
+ const { todos } = this.state;
+ const id = index++;
+
+ this.setState({
+ todos: { ...todos, [id]: { label } }
+ });
+ };
+
+ private _remove = id => {
+ const newTodos = { ...this.state.todos };
+ delete newTodos[id];
+
+ this.setState({
+ todos: newTodos
+ });
+ };
+
+ private _complete = id => {
+ const newTodos = { ...this.state.todos };
+ newTodos[id].completed = !newTodos[id].completed;
+
+ this.setState({
+ todos: newTodos
+ });
+ };
+
+ private _edit = (id, label) => {
+ const newTodos = { ...this.state.todos };
+ newTodos[id] = { ...newTodos[id], label };
+
+ this.setState({
+ todos: newTodos
+ });
+ };
+
+ private _clear = () => {
+ const { todos } = this.state;
+ const newTodos = {};
+
+ Object.keys(this.state.todos).forEach(id => {
+ if (!todos[id].completed) {
+ newTodos[id] = todos[id];
+ }
+ });
+
+ this.setState({
+ todos: newTodos
+ });
+ };
+
+ private _setFilter = filter => {
+ this.setState({
+ filter: filter
+ });
+ };
+}
diff --git a/step2-03/exercise/src/components/TodoFooter.tsx b/step2-03/exercise/src/components/TodoFooter.tsx
new file mode 100644
index 0000000..6a44d83
--- /dev/null
+++ b/step2-03/exercise/src/components/TodoFooter.tsx
@@ -0,0 +1,23 @@
+import React from 'react';
+import { Text } from '@uifabric/experiments';
+import { Stack } from 'office-ui-fabric-react';
+import { Store } from '../store';
+import { DefaultButton } from 'office-ui-fabric-react';
+
+interface TodoFooterProps {
+ clear: () => void;
+ todos: Store['todos'];
+}
+
+export const TodoFooter = (props: TodoFooterProps) => {
+ const itemCount = Object.keys(props.todos).filter(id => !props.todos[id].completed).length;
+
+ return (
+
+
+ {itemCount} item{itemCount > 1 ? 's' : ''} left
+
+ props.clear()}>Clear Completed
+
+ );
+};
diff --git a/step2-03/exercise/src/components/TodoHeader.tsx b/step2-03/exercise/src/components/TodoHeader.tsx
new file mode 100644
index 0000000..7a9cae2
--- /dev/null
+++ b/step2-03/exercise/src/components/TodoHeader.tsx
@@ -0,0 +1,58 @@
+import React from 'react';
+import { Text } from '@uifabric/experiments';
+import { Stack } from 'office-ui-fabric-react';
+import { Pivot, PivotItem, TextField, PrimaryButton } from 'office-ui-fabric-react';
+import { FilterTypes } from '../store';
+
+interface TodoHeaderProps {
+ addTodo: (label: string) => void;
+ setFilter: (filter: FilterTypes) => void;
+ filter: FilterTypes;
+}
+
+interface TodoHeaderState {
+ labelInput: string;
+}
+
+export class TodoHeader extends React.Component {
+ constructor(props: TodoHeaderProps) {
+ super(props);
+ this.state = { labelInput: undefined };
+ }
+
+ render() {
+ return (
+
+
+ todos
+
+
+
+
+
+
+ Add
+
+
+
+
+
+
+
+
+ );
+ }
+
+ private onAdd = () => {
+ this.props.addTodo(this.state.labelInput);
+ this.setState({ labelInput: undefined });
+ };
+
+ private onChange = (evt: React.FormEvent, newValue: string) => {
+ this.setState({ labelInput: newValue });
+ };
+
+ private onFilter = (item: PivotItem) => {
+ this.props.setFilter(item.props.headerText as FilterTypes);
+ };
+}
diff --git a/step2-03/exercise/src/components/TodoList.tsx b/step2-03/exercise/src/components/TodoList.tsx
new file mode 100644
index 0000000..805bd8f
--- /dev/null
+++ b/step2-03/exercise/src/components/TodoList.tsx
@@ -0,0 +1,27 @@
+import React from 'react';
+import { Stack } from 'office-ui-fabric-react';
+import { TodoListItem } from './TodoListItem';
+import { Store, FilterTypes } from '../store';
+
+interface TodoListProps {
+ complete: (id: string) => void;
+ remove: (id: string) => void;
+ todos: Store['todos'];
+ filter: FilterTypes;
+ edit: (id: string, label: string) => void;
+}
+
+export const TodoList = (props: TodoListProps) => {
+ const { filter, todos, complete, remove, edit } = props;
+ const filteredTodos = Object.keys(todos).filter(id => {
+ return filter === 'all' || (filter === 'completed' && todos[id].completed) || (filter === 'active' && !todos[id].completed);
+ });
+
+ return (
+
+ {filteredTodos.map(id => (
+
+ ))}
+
+ );
+};
diff --git a/step2-03/exercise/src/components/TodoListItem.tsx b/step2-03/exercise/src/components/TodoListItem.tsx
new file mode 100644
index 0000000..030aa73
--- /dev/null
+++ b/step2-03/exercise/src/components/TodoListItem.tsx
@@ -0,0 +1,75 @@
+import React from 'react';
+import { Stack, Checkbox, IconButton, TextField, DefaultButton } from 'office-ui-fabric-react';
+import { Store } from '../store';
+
+interface TodoListItemProps {
+ id: string;
+ todos: Store['todos'];
+ remove: (id: string) => void;
+ complete: (id: string) => void;
+ edit: (id: string, label: string) => void;
+}
+
+interface TodoListItemState {
+ editing: boolean;
+ editLabel: string;
+}
+
+export class TodoListItem extends React.Component {
+ constructor(props: TodoListItemProps) {
+ super(props);
+ this.state = { editing: false, editLabel: undefined };
+ }
+
+ render() {
+ const { todos, id, complete, remove } = this.props;
+ const item = todos[id];
+
+ return (
+
+ {!this.state.editing && (
+ <>
+ complete(id)} />
+
+
+ remove(id)} />
+
+ >
+ )}
+
+ {this.state.editing && (
+
+
+
+
+
+ Save
+
+
+ )}
+
+ );
+ }
+
+ private onEdit = () => {
+ const { todos, id } = this.props;
+ const { label } = todos[id];
+
+ this.setState({
+ editing: true,
+ editLabel: this.state.editLabel || label
+ });
+ };
+
+ private onDoneEdit = () => {
+ this.props.edit(this.props.id, this.state.editLabel);
+ this.setState({
+ editing: false,
+ editLabel: undefined
+ });
+ };
+
+ private onChange = (evt: React.FormEvent, newValue: string) => {
+ this.setState({ editLabel: newValue });
+ };
+}
diff --git a/step2-03/exercise/src/index.tsx b/step2-03/exercise/src/index.tsx
new file mode 100644
index 0000000..2587243
--- /dev/null
+++ b/step2-03/exercise/src/index.tsx
@@ -0,0 +1,10 @@
+import React from 'react';
+import ReactDOM from 'react-dom';
+import { TodoApp } from './components/TodoApp';
+import { initializeIcons } from '@uifabric/icons';
+
+// Initializes the UI Fabric icons that we can use
+// Choose one from this list: https://developer.microsoft.com/en-us/fabric#/styles/icons
+initializeIcons();
+
+ReactDOM.render(, document.getElementById('app'));
diff --git a/step2-03/exercise/src/store/index.ts b/step2-03/exercise/src/store/index.ts
new file mode 100644
index 0000000..221b5f4
--- /dev/null
+++ b/step2-03/exercise/src/store/index.ts
@@ -0,0 +1,14 @@
+export type FilterTypes = 'all' | 'active' | 'completed';
+
+export interface TodoItem {
+ label: string;
+ completed: boolean;
+}
+
+export interface Store {
+ todos: {
+ [id: string]: TodoItem;
+ };
+
+ filter: FilterTypes;
+}