diff --git a/src/app/degree-planner/degree-planner.component.html b/src/app/degree-planner/degree-planner.component.html
index 98175f91db73df425b0204c55a776e1160f0ca4d..34a952fbded76f1257a71f83bab90ba5ced9beee 100644
--- a/src/app/degree-planner/degree-planner.component.html
+++ b/src/app/degree-planner/degree-planner.component.html
@@ -139,6 +139,11 @@
           fxLayoutAlign="start stretch"
           style="margin:24px 24px 72px 24px">
           <div id="year-mask" *ngIf="(isLoadingPlan$ | async)"></div>
+          <div id="accordion-controls">
+            <button mat-button color="primary" (click)="toggleAllYears(true)" aria-label="Expand All Years">Expand All</button>
+            <span>|</span>
+            <button mat-button color="primary" (click)="toggleAllYears(false)" aria-label="Collapse All Years">Collapse All</button>
+          </div>
           <mat-accordion multi="true">
             <cse-year-container
               *ngFor="let yearCode of yearCodes$ | async; trackBy: trackYearCodes"
diff --git a/src/app/degree-planner/degree-planner.component.scss b/src/app/degree-planner/degree-planner.component.scss
index 3be88ddb787797d48044711c0117b84fbef27c18..8b5f2b7aad08a0c153d9ce8d3066f49d72bff230 100644
--- a/src/app/degree-planner/degree-planner.component.scss
+++ b/src/app/degree-planner/degree-planner.component.scss
@@ -1,3 +1,5 @@
+@import 'assets/material-theme.scss';
+
 #plans-container {
   height: calc(100vh - 112px);
 
@@ -103,3 +105,8 @@ mat-sidenav {
 #year-mask {
   display: none;
 }
+
+#accordion-controls {
+  text-align: right;
+  color: map-get($uw-primary, 500);
+}
diff --git a/src/app/degree-planner/degree-planner.component.ts b/src/app/degree-planner/degree-planner.component.ts
index fa2374fb9a8480c6fedd96c70c20a57dfad44598..c149767fc8f13b7044b8c597918cd68cfb376479 100644
--- a/src/app/degree-planner/degree-planner.component.ts
+++ b/src/app/degree-planner/degree-planner.component.ts
@@ -31,6 +31,8 @@ import {
   CloseCourseSearch,
   CloseSidenav,
   OpenSidenav,
+  ExpandAcademicYear,
+  CollapseAcademicYear,
 } from './store/actions/ui.actions';
 import { YearCode } from '@app/core/models/termcode';
 import { ConstantsService } from './services/constants.service';
@@ -269,6 +271,13 @@ export class DegreePlannerComponent implements OnInit {
   public trackYearCodes(_index: number, yearCode: YearCode) {
     return yearCode.toString();
   }
+
+  public toggleAllYears(expand: boolean) {
+    const event = expand
+      ? new ExpandAcademicYear()
+      : new CollapseAcademicYear();
+    this.store.dispatch(event);
+  }
 }
 
 const isntUndefined = <T>(anything: T | undefined): anything is T => {
diff --git a/src/app/degree-planner/store/actions/ui.actions.ts b/src/app/degree-planner/store/actions/ui.actions.ts
index 220b0b0e41174af7bd75d5de6e8c41d1f11db33d..1e208197b4e7753f99b00264e7484f39d31b7c60 100644
--- a/src/app/degree-planner/store/actions/ui.actions.ts
+++ b/src/app/degree-planner/store/actions/ui.actions.ts
@@ -23,12 +23,12 @@ export class ToggleAcademicYear implements Action {
 
 export class ExpandAcademicYear implements Action {
   public readonly type = UIActionTypes.ExpandAcademicYear;
-  constructor(public payload: { yearCode: YearCode }) {}
+  constructor(public payload?: { yearCode: YearCode }) {}
 }
 
 export class CollapseAcademicYear implements Action {
   public readonly type = UIActionTypes.CollapseAcademicYear;
-  constructor(public payload: { yearCode: YearCode }) {}
+  constructor(public payload?: { yearCode: YearCode }) {}
 }
 
 export class OpenCourseSearch implements Action {
diff --git a/src/app/degree-planner/store/reducer.ts b/src/app/degree-planner/store/reducer.ts
index fc23f03e04b32046d7965c6a791c60c4b111b5cf..16868620f5cb10ceabbf36f603786c4689e608ff 100644
--- a/src/app/degree-planner/store/reducer.ts
+++ b/src/app/degree-planner/store/reducer.ts
@@ -150,31 +150,33 @@ export function degreePlannerReducer(
     }
 
     case UIActionTypes.ExpandAcademicYear: {
-      const yearCode = action.payload.yearCode;
-      return {
-        ...state,
-        visibleYears: {
-          ...state.visibleYears,
-          [yearCode.toString()]: {
-            ...state.visibleYears[yearCode.toString()],
-            isExpanded: true,
-          },
-        },
-      };
+      const yearCode = action.payload ? action.payload.yearCode : undefined;
+      const newState = { ...state };
+
+      if (yearCode) {
+        newState.visibleYears[yearCode.toString()].isExpanded = true;
+      } else {
+        Object.entries(newState.visibleYears).forEach(([code, year]) => {
+          newState.visibleYears[code].isExpanded = true;
+        });
+      }
+
+      return newState;
     }
 
     case UIActionTypes.CollapseAcademicYear: {
-      const yearCode = action.payload.yearCode;
-      return {
-        ...state,
-        visibleYears: {
-          ...state.visibleYears,
-          [yearCode.toString()]: {
-            ...state.visibleYears[yearCode.toString()],
-            isExpanded: false,
-          },
-        },
-      };
+      const yearCode = action.payload ? action.payload.yearCode : undefined;
+      const newState = { ...state };
+
+      if (yearCode) {
+        newState.visibleYears[yearCode.toString()].isExpanded = false;
+      } else {
+        Object.entries(newState.visibleYears).forEach(([code, year]) => {
+          newState.visibleYears[code].isExpanded = false;
+        });
+      }
+
+      return newState;
     }
 
     /**