diff --git a/lms/static/scripts/frontend_apps/api-types.ts b/lms/static/scripts/frontend_apps/api-types.ts
index 1d3665f458..4d1574f915 100644
--- a/lms/static/scripts/frontend_apps/api-types.ts
+++ b/lms/static/scripts/frontend_apps/api-types.ts
@@ -153,12 +153,21 @@ export type BaseDashboardStats = {
   replies: number;
 };
 
+/**
+ * Response for `/api/dashboard/courses/{course_id}` call.
+ */
+export type Course = {
+  id: number;
+  title: string;
+};
+
 /**
  * Response for `/api/dashboard/assignments/{assignment_id}` call.
  */
 export type Assignment = {
   id: number;
   title: string;
+  course: Course;
 };
 
 /**
@@ -170,21 +179,10 @@ export type StudentStats = BaseDashboardStats & {
 
 export type StudentsStats = StudentStats[];
 
-/**
- * Response for `/api/dashboard/courses/{course_id}` call.
- */
-export type Course = {
-  id: number;
-  title: string;
-};
-
 /**
  * Response for `/api/dashboard/courses/{course_id}/assignments/stats` call.
  */
-export type AssignmentStats = {
-  id: number;
-  title: string;
-  course: Course;
+export type AssignmentStats = Assignment & {
   stats: BaseDashboardStats;
 };
 
diff --git a/lms/static/scripts/frontend_apps/components/dashboard/AssignmentActivity.tsx b/lms/static/scripts/frontend_apps/components/dashboard/AssignmentActivity.tsx
index b7eac381fe..40ee2fc537 100644
--- a/lms/static/scripts/frontend_apps/components/dashboard/AssignmentActivity.tsx
+++ b/lms/static/scripts/frontend_apps/components/dashboard/AssignmentActivity.tsx
@@ -1,9 +1,4 @@
-import {
-  Card,
-  CardContent,
-  CardHeader,
-  CardTitle,
-} from '@hypothesis/frontend-shared';
+import { Card, CardContent, CardHeader } from '@hypothesis/frontend-shared';
 import { useParams } from 'wouter-preact';
 
 import type { Assignment, StudentsStats } from '../../api-types';
@@ -11,6 +6,7 @@ import { useConfig } from '../../config';
 import { useAPIFetch } from '../../utils/api';
 import { formatDateTime } from '../../utils/date';
 import { replaceURLParams } from '../../utils/url';
+import DashboardBreadcrumbs from './DashboardBreadcrumbs';
 import OrderableActivityTable from './OrderableActivityTable';
 
 /**
@@ -27,21 +23,31 @@ export default function AssignmentActivity() {
     replaceURLParams(routes.assignment_stats, { assignment_id: assignmentId }),
   );
 
-  const title = `Assignment: ${assignment.data?.title}`;
-
   return (
     <Card>
-      <CardHeader fullWidth>
-        <CardTitle tagName="h2" data-testid="title">
+      <CardHeader fullWidth classes="flex-col !gap-x-0 !items-start">
+        {assignment.data && (
+          <div className="mb-3 mt-1">
+            <DashboardBreadcrumbs
+              links={[
+                {
+                  title: assignment.data.course.title,
+                  href: `/courses/${assignment.data.course.id}`,
+                },
+              ]}
+            />
+          </div>
+        )}
+        <h2 data-testid="title" className="text-lg text-brand font-semibold">
           {assignment.isLoading && 'Loading...'}
           {assignment.error && 'Could not load assignment title'}
-          {assignment.data && title}
-        </CardTitle>
+          {assignment.data && assignment.data.title}
+        </h2>
       </CardHeader>
       <CardContent>
         <OrderableActivityTable
           loading={students.isLoading}
-          title={assignment.isLoading ? 'Loading...' : title}
+          title={assignment.data?.title ?? 'Loading...'}
           emptyMessage={
             students.error ? 'Could not load students' : 'No students found'
           }
diff --git a/lms/static/scripts/frontend_apps/components/dashboard/DashboardBreadcrumbs.tsx b/lms/static/scripts/frontend_apps/components/dashboard/DashboardBreadcrumbs.tsx
new file mode 100644
index 0000000000..bd0f78f6b4
--- /dev/null
+++ b/lms/static/scripts/frontend_apps/components/dashboard/DashboardBreadcrumbs.tsx
@@ -0,0 +1,65 @@
+import {
+  ArrowLeftIcon,
+  CaretRightIcon,
+  Link,
+} from '@hypothesis/frontend-shared';
+import classnames from 'classnames';
+import { Fragment } from 'preact';
+import { Link as RouterLink } from 'wouter-preact';
+
+type BreadcrumbLink = {
+  title: string;
+  href: string;
+};
+
+export type DashboardBreadcrumbsProps = {
+  links: BreadcrumbLink[];
+};
+
+function BreadcrumbLink({
+  title,
+  href,
+  classes,
+}: BreadcrumbLink & { classes?: string }) {
+  return (
+    <RouterLink href={href} asChild>
+      <Link
+        underline="hover"
+        variant="text-light"
+        classes={classnames('truncate md:max-w-[350px]', classes)}
+      >
+        <ArrowLeftIcon className="md:hidden mr-2 inline" />
+        {title}
+      </Link>
+    </RouterLink>
+  );
+}
+
+export default function DashboardBreadcrumbs({
+  links,
+}: DashboardBreadcrumbsProps) {
+  return (
+    <div
+      className="font-bold flex flex-col md:flex-row gap-0.5"
+      data-testid="breadcrumbs-container"
+    >
+      {links.map(({ title, href }, index) => {
+        const isLastLink = index === links.length - 1;
+
+        return (
+          <Fragment key={`${index}${href}`}>
+            <BreadcrumbLink
+              href={href}
+              title={title}
+              classes={classnames('md:inline', {
+                // In mobile devices, show only the last link
+                hidden: !isLastLink,
+              })}
+            />
+            {index !== links.length - 1 && <CaretRightIcon />}
+          </Fragment>
+        );
+      })}
+    </div>
+  );
+}
diff --git a/lms/static/scripts/frontend_apps/components/dashboard/test/AssignmentActivity-test.js b/lms/static/scripts/frontend_apps/components/dashboard/test/AssignmentActivity-test.js
index eccd200d79..2f633a569c 100644
--- a/lms/static/scripts/frontend_apps/components/dashboard/test/AssignmentActivity-test.js
+++ b/lms/static/scripts/frontend_apps/components/dashboard/test/AssignmentActivity-test.js
@@ -37,7 +37,14 @@ describe('AssignmentActivity', () => {
   beforeEach(() => {
     fakeUseAPIFetch = sinon.stub().callsFake(url => ({
       isLoading: false,
-      data: url.endsWith('stats') ? students : { title: 'The title' },
+      data: url.endsWith('stats')
+        ? students
+        : {
+            title: 'The title',
+            course: {
+              title: 'The course',
+            },
+          },
     }));
     fakeConfig = {
       dashboard: {
@@ -72,7 +79,7 @@ describe('AssignmentActivity', () => {
     fakeUseAPIFetch.returns({ isLoading: true });
 
     const wrapper = createComponent();
-    const titleElement = wrapper.find('CardTitle[data-testid="title"]');
+    const titleElement = wrapper.find('[data-testid="title"]');
     const tableElement = wrapper.find('OrderableActivityTable');
 
     assert.equal(titleElement.text(), 'Loading...');
@@ -83,7 +90,7 @@ describe('AssignmentActivity', () => {
     fakeUseAPIFetch.returns({ error: new Error('Something failed') });
 
     const wrapper = createComponent();
-    const titleElement = wrapper.find('CardTitle[data-testid="title"]');
+    const titleElement = wrapper.find('[data-testid="title"]');
     const tableElement = wrapper.find('OrderableActivityTable');
 
     assert.equal(titleElement.text(), 'Could not load assignment title');
@@ -92,9 +99,9 @@ describe('AssignmentActivity', () => {
 
   it('shows expected title', () => {
     const wrapper = createComponent();
-    const titleElement = wrapper.find('CardTitle[data-testid="title"]');
+    const titleElement = wrapper.find('[data-testid="title"]');
     const tableElement = wrapper.find('OrderableActivityTable');
-    const expectedTitle = `Assignment: The title`;
+    const expectedTitle = 'The title';
 
     assert.equal(titleElement.text(), expectedTitle);
     assert.equal(tableElement.prop('title'), expectedTitle);
diff --git a/lms/static/scripts/frontend_apps/components/dashboard/test/DashboardBreadcrumbs-test.js b/lms/static/scripts/frontend_apps/components/dashboard/test/DashboardBreadcrumbs-test.js
new file mode 100644
index 0000000000..95235b50dc
--- /dev/null
+++ b/lms/static/scripts/frontend_apps/components/dashboard/test/DashboardBreadcrumbs-test.js
@@ -0,0 +1,34 @@
+import { checkAccessibility } from '@hypothesis/frontend-testing';
+import { mount } from 'enzyme';
+
+import DashboardBreadcrumbs from '../DashboardBreadcrumbs';
+
+describe('DashboardBreadcrumbs', () => {
+  function createComponent(props = {}) {
+    return mount(<DashboardBreadcrumbs {...props} />);
+  }
+
+  [['foo', 'bar'], [], ['one', 'two', 'three']].forEach(links => {
+    it('shows expected amount of links', () => {
+      const wrapper = createComponent({
+        title: 'Hello world',
+        links: links.map(title => ({ title, href: `/${title}` })),
+      });
+
+      assert.equal(wrapper.find('BreadcrumbLink').length, links.length);
+    });
+  });
+
+  it(
+    'should pass a11y checks',
+    checkAccessibility({
+      content: () =>
+        createComponent({
+          links: [
+            { title: 'Foo', href: '/foo' },
+            { title: 'Bar', href: '/bar' },
+          ],
+        }),
+    }),
+  );
+});