diff --git a/lib/KBreadcrumbs.vue b/lib/KBreadcrumbs.vue
index 6e7416111..6cc1d9b70 100644
--- a/lib/KBreadcrumbs.vue
+++ b/lib/KBreadcrumbs.vue
@@ -1,378 +1,110 @@
 <template>
-
-  <div
-    v-show="showSingleItem || crumbs.length > 1"
-    :class="{ 'breadcrumbs-collapsed': collapsedCrumbs.length }"
-  >
-    <nav class="breadcrumbs" v-bind="$attrs" :aria-label="$attrs.ariaLabel">
-      <div
-        v-show="collapsedCrumbs.length"
-        class="breadcrumbs-dropdown-wrapper"
+  <KListWithOverflow
+  overflowDirection="start"
+  :items="breadcrumbs"
+>
+  <template #item="{ item }">
+    <li>
+      <KRouterLink
+        v-if="item.link"
+        :text="item.text"
+        :to="item.link"
       >
-        <KIconButton
-          size="small"
-          :icon="showDropdown ? 'chevronUp' : 'chevronDown'"
-          appearance="raised-button"
-          @click="showDropdown = !showDropdown"
-        />
-        <div
-          v-if="showDropdown"
-          class="breadcrumbs-dropdown"
-          :style="{ background: $themeTokens.surface }"
-        >
-          <ol class="breadcrumbs-dropdown-items">
-            <li
-              v-for="(crumb, index) in collapsedCrumbs"
-              :key="index"
-              class="breadcrumbs-dropdown-item"
-            >
-              <KRouterLink
-                v-if="crumb.link"
-                class="krouter-item"
-                :text="crumb.text"
-                :to="crumb.link"
-              >
-                <template #text="{ text }">
-                  <span class="breadcrumbs-crumb-text" dir="auto">{{ text }}</span>
-                </template>
-              </KRouterLink>
-              <span v-else dir="auto">{{ crumb.text }}</span>
-            </li>
-          </ol>
-        </div>
-      </div>
-
-      <ol class="breadcrumbs-visible-items">
-        <template v-for="(crumb, index) in crumbs">
-          <li
-            v-if="index !== crumbs.length - 1"
-            v-show="!crumb.collapsed"
-            :key="index"
-            class="breadcrumbs-visible-item breadcrumbs-visible-item-notlast"
-          >
-            <KRouterLink
-              v-if="crumb.link"
-              :text="crumb.text"
-              :to="crumb.link"
-              dir="auto"
-            >
-              <template #text="{ text }">
-                <span class="breadcrumbs-crumb-text">{{ text }}</span>
-              </template>
-            </KRouterLink>
-            <span v-else>{{ crumb.text }}</span>
-          </li>
-
-          <li
-            v-else
-            :key="index"
-            class="breadcrumb-visible-item-last breadcrumbs-visible-item"
-          >
-            <span
-              class="breadcrumbs-crumb-text"
-              :style="{ maxWidth: lastBreadcrumbMaxWidth }"
-              dir="auto"
-            >
-              {{ crumb.text }}
-            </span>
-          </li>
+        <template #text="{ text }">
+          <span >{{ text }}</span>
         </template>
-      </ol>
-    </nav>
-
-
-    <!-- This is a duplicate of breacrumbs-visible-items to help to reference sizes. -->
-    <div class="breadcrumbs breadcrumbs-offscreen" aria-hidden="true">
-      <ol class="breadcrumbs-visible-items">
-        <template v-for="(crumb, index) in crumbs">
-          <li
-            v-if="index !== crumbs.length - 1"
-            :ref="`crumb${index}`"
-            :key="index"
-            class="breadcrumbs-visible-item breadcrumbs-visible-item-notlast"
-          >
-            <KRouterLink v-if="crumb.link" :text="crumb.text" :to="crumb.link" tabindex="-1">
-              <template #text="{ text }">
-                <span class="breadcrumbs-crumb-text">{{ text }}</span>
-              </template>
-            </KRouterLink>
-            <span v-else>{{ crumb.text }}</span>
-          </li>
-
-          <li
-            v-else
-            :ref="`crumb${index}`"
-            :key="index"
-            class="breadcrumb-visible-item-last breadcrumbs-visible-item"
-          >
-            <span
-              class="breadcrumbs-crumb-text"
-              :style="{ maxWidth: lastBreadcrumbMaxWidth }"  
-            >
-              {{ crumb.text }}
-            </span>
-          </li>
-        </template>
-      </ol>
-    </div>
-  </div>
-
+      </KRouterLink>
+      <span v-else>{{ item.text }}</span>
+    </li>
+  </template>
+  <template #more="{ overflowItems }">
+    <KIconButton
+      size="small"
+      icon="chevronUp"
+      appearance="raised-button"
+    >
+      <template #menu>
+        <KDropdownMenu
+          :options="overflowItems"
+        />
+      </template>
+    </KIconButton>
+    <span>
+      >
+    </span>
+  </template>
+</KListWithOverflow>
 </template>
 
-
 <script>
-
-  import filter from 'lodash/filter';
-  import startsWith from 'lodash/startsWith';
-  import throttle from 'lodash/throttle';
-  import every from 'lodash/every';
-  import keys from 'lodash/keys';
-  import KResponsiveElementMixin from './KResponsiveElementMixin';
-
-  const DROPDOWN_BTN_WIDTH = 55;
-  const DEFAULT_LAST_BREADCRUMB_MAX_WIDTH = 300;
-
-  function validateLinkObject(object) {
-    const validKeys = ['name', 'path', 'params', 'query'];
-    return every(keys(object), key => validKeys.includes(key));
-  }
-
-  /**
-   * Used to aid deeply nested navigation of content channels, topics, and resources
-   */
-  export default {
-    name: 'KBreadcrumbs',
-    mixins: [KResponsiveElementMixin],
-    inheritAttrs: false,
-    props: {
-      /**
-       * An array of objects, each with a `text` attribute (String) and a
-       * `link` attribute (vue router link object). The `link` attribute
-       * of the last item in the array is optional and ignored. The `link`
-       * attribute can be set to `null` which will render the breadcrumb only
-       * as text, regardless of its position in the breadcrumb.
-       */
-      items: {
-        type: Array,
-        required: true,
-        validator(crumbItems) {
-          // All must have text
-          if (!crumbItems.every(crumb => Boolean(crumb.text))) {
-            return false;
-          }
-          // If link is truthy make sure it is a valid router link
-          return crumbItems.every(crumb => !crumb.link || validateLinkObject(crumb.link));
-        },
-      },
-      /**
-       * By default, the breadcrums will be hidden when the length of items is 1.
-       * When set to `true`, a breadcrumb will be shown even when there is only one.
-       */
-      showSingleItem: {
-        type: Boolean,
-        default: false,
-      },
+import KListWithOverflow from './KListWithOverflow.vue';
+import KDropdownMenu from './KDropdownMenu.vue';
+export default {
+  name: 'KBreadcrumbs',
+  props: {
+    breadcrumbs: {
+      type: Array,
+      required: true,
     },
-
-    data: () => ({
-      // Array of crumb objects.
-      // Each object contains:
-      // text, router-link 'to' object, vue ref, and its collapsed state
-      crumbs: [],
+  },
+  components: {
+    KListWithOverflow,
+    KDropdownMenu
+  },
+  data() {
+    return {
       showDropdown: false,
-      lastBreadcrumbMaxWidth: `${DEFAULT_LAST_BREADCRUMB_MAX_WIDTH}px`,
-    }),
-    computed: {
-      collapsedCrumbs() {
-        return this.crumbs.filter(crumb => crumb.collapsed === true).reverse();
-      },
-      parentWidth() {
-        return this.elementWidth;
-      },
-    },
-    watch: {
-      items(val) {
-        this.crumbs = Array.from(val);
-        this.attachRefs();
-      },
-    },
-    created() {
-      this.crumbs = Array.from(this.items);
-    },
-    mounted() {
-      this.attachRefs();
-      // The throttled update function is defined here and not as a method on purpose
-      // since having it defined as a method on the options object would cause problems
-      // when there are more KBreadcrumbs instances rendered on one page.
-      // In such a scenario, all instances would share the same throttled function
-      // resulting in some instances not being updated when they should be.
-      // This is happening because of how the Vue component constructor and instances are built.
-      // Having it defined in the context of the `mounted` function ensures that each component
-      // instance will have its own throttled update function.
-      const throttledUpdateCrumbs = throttle(this.updateCrumbs, 100);
-      this.$watch('parentWidth', throttledUpdateCrumbs);
-    },
-    methods: {
-      attachRefs() {
-        this.$nextTick(() => {
-          const crumbRefs = filter(this.$refs, (value, key) => startsWith(key, 'crumb'));
-          this.crumbs = this.crumbs.map((crumb, index) => {
-            const updatedCrumb = crumb;
-            updatedCrumb.ref = crumbRefs[index];
-            return updatedCrumb;
-          });
-          this.updateCrumbs();
-        });
-      },
-      updateCrumbs() {
-        if (this.crumbs.length) {
-          // needs to be reset before another re-calculation
-          // otherwise calculactions below won't be precise
-          this.lastBreadcrumbMaxWidth = `${DEFAULT_LAST_BREADCRUMB_MAX_WIDTH}px`;
-
-          this.$nextTick(() => {
-            const tempCrumbs = Array.from(this.crumbs);
-            let lastCrumbWidth = Math.ceil(tempCrumbs.pop().ref[0].getBoundingClientRect().width);
-            let remainingWidth = this.parentWidth - DROPDOWN_BTN_WIDTH - lastCrumbWidth;
-            let trackingIndex = this.crumbs.length - 2;
-
-            while (tempCrumbs.length) {
-              if (remainingWidth <= 0) {
-                tempCrumbs.forEach((crumb, index) => {
-                  const updatedCrumb = crumb;
-                  updatedCrumb.collapsed = true;
-                  this.crumbs.splice(index, 1, updatedCrumb);
-                });
-                break;
-              }
-
-              lastCrumbWidth = Math.ceil(
-                tempCrumbs[tempCrumbs.length - 1].ref[0].getBoundingClientRect().width
-              );
-
-              if (lastCrumbWidth > remainingWidth) {
-                tempCrumbs.forEach((crumb, index) => {
-                  const updatedCrumb = crumb;
-                  updatedCrumb.collapsed = true;
-                  this.crumbs.splice(index, 1, updatedCrumb);
-                });
-                break;
-              }
-
-              remainingWidth -= lastCrumbWidth;
-              const lastCrumb = tempCrumbs.pop();
-              lastCrumb.collapsed = false;
-              this.crumbs.splice(trackingIndex, 1, lastCrumb);
-              trackingIndex -= 1;
-            }
-
-            // Allow the last breadcrumb use all space available
-            // Fixes https://github.com/learningequality/kolibri-design-system/issues/198
-            // and https://github.com/learningequality/kolibri/issues/6918
-            if (remainingWidth > 0) {
-              this.lastBreadcrumbMaxWidth = `${DEFAULT_LAST_BREADCRUMB_MAX_WIDTH +
-                remainingWidth}px`;
-            }
-          });
-        }
-      },
-    },
-  };
-
-</script>
-
-
-<style lang="scss" scoped>
-
-  @import './styles/definitions';
-  $crumb-max-width: 300px;
-
-  .breadcrumbs {
-    height: 32px;
-    margin-top: 8px;
-    margin-bottom: 8px;
-    font-size: 16px;
-    font-weight: bold;
-    line-height: 32px;
-    white-space: nowrap;
-  }
-
-  .breadcrumbs-crumb-text {
-    display: inline-block;
-    width: 100%;
-    max-width: $crumb-max-width;
-    overflow: hidden;
-    text-overflow: ellipsis;
-    white-space: nowrap;
-    vertical-align: bottom;
-  }
-
-  .breadcrumbs-dropdown-wrapper {
-    display: inline-block;
-
-    &::after {
-      margin-right: 8px;
-      margin-left: 8px;
-      content: '›';
+    };
+  },
+  methods: {
+    toggleDropdown() {
+      this.showDropdown = !this.showDropdown; 
     }
-  }
-
-  .breadcrumbs-dropdown {
-    @extend %dropshadow-2dp;
-
-    position: absolute;
-    z-index: 8;
-    max-width: 100%;
-    padding: 16px;
-    font-weight: bold;
-  }
-
-  .breadcrumbs-dropdown-items {
-    padding: 0;
-    margin: 0;
-    list-style: none;
-  }
-
-  .breadcrumbs-dropdown-item {
-    display: block;
-    padding-top: 8px;
-    padding-bottom: 8px;
-
-    .krouter-item {
-      width: 100%;
-    }
-  }
-
-  .breadcrumbs-visible-items {
-    display: inline-block;
-    width: 100%;
-    padding: 0;
-    margin: 0;
-    white-space: nowrap;
-    list-style: none;
-
-    .breadcrumbs-collapsed & {
-      // account for dropdown button width
-      width: calc(100% - 55px);
-    }
-  }
-
-  .breadcrumbs-visible-item {
-    display: inline-block;
-    max-width: 100%;
-  }
+  },
+};
+</script>
 
-  .breadcrumbs-visible-item-notlast {
-    &::after {
-      margin-right: 8px;
-      margin-left: 8px;
-      content: '›';
-    }
-  }
 
-  .breadcrumbs-offscreen {
-    position: absolute;
-    left: -1000em;
-  }
+<style  scoped>
+
+.breadcrumbs {
+  height: 32px;
+  width: auto;
+  margin-top: 8px;
+  margin-bottom: 8px;
+  font-size: 16px;
+  font-weight: bold;
+  line-height: 32px;
+  white-space: nowrap;
+}
+
+.link {
+  color: blue;
+  padding-left: 10px;
+}
+
+.text {
+  color: black;
+  padding-left: 10px;
+}
+
+.icon {
+  color: black;
+  padding-left: 5;
+  padding-right: 5;
+}
+
+.more-button {
+  color: blue;
+  cursor: pointer;
+}
+
+.overflowed-items {
+  position: absolute;
+  background-color: #fff;
+  border: 1px solid #ddd;
+  padding: 10px;
+  z-index: 1;
+}
 
 </style>
diff --git a/lib/KListWithOverflow.vue b/lib/KListWithOverflow.vue
index 5b65fda4a..564e78854 100644
--- a/lib/KListWithOverflow.vue
+++ b/lib/KListWithOverflow.vue
@@ -28,6 +28,7 @@
     <div
       ref="moreButtonWrapper"
       class="more-button-wrapper"
+      :class="{ 'start-button': overflowDirection === 'start' }"
     >
       <!-- @slot Slot responsible of rendering the "see more" button. This slot receives as prop a list `overflowItems` with items that dont fit into the visible list.-->
       <slot
@@ -70,12 +71,20 @@
         type: [Object, String],
         default: null,
       },
+      overflowDirection: {
+        type: String,
+        default: 'end',
+        validator(value) {
+          return ['start', 'end'].includes(value);
+        },
+      },
     },
     data() {
       return {
         mounted: false,
         overflowItems: [],
         // default to true just to measure its width at first render
+        visibleItems: [],
         isMoreButtonVisible: true,
         moreButtonWidth: 0,
       };
@@ -152,21 +161,24 @@
           itemsSizes.push(itemSize);
         }
 
+        if (this.overflowDirection === 'start') {
+              itemsSizes.reverse();
+        }
+        const indexSequence = [...Array(list.children.length).keys()];
+        const directionIndexes =
+          this.overflowDirection === 'start' ? indexSequence.reverse() : indexSequence;
+
         const overflowItemsIdx = [];
-        for (let i = 0; i < list.children.length; i++) {
-          const item = list.children[i];
-          const itemWidth = itemsSizes[i].width;
 
-          // If the item dont fit in the available space or if we have already
-          // overflowed items, we hide it. This means that once one item overflows,
-          // all the following items will be hidden.
+        directionIndexes.forEach((i) => {
+          const itemWidth = itemsSizes[i].width;
           if (itemWidth >= availableWidth || overflowItemsIdx.length > 0) {
             overflowItemsIdx.push(i);
-            item.style.visibility = 'hidden';
-            item.style.position = 'absolute';
+            list.children[i].style.visibility = 'hidden';
+            list.children[i].style.position = 'absolute';
           } else {
-            item.style.visibility = 'visible';
-            item.style.position = 'unset';
+            list.children[i].style.visibility = 'visible';
+            list.children[i].style.position = 'unset';
             maxWidth += itemWidth;
             availableWidth -= itemWidth;
             const itemHeight = itemsSizes[i].height;
@@ -174,7 +186,7 @@
               maxHeight = itemHeight;
             }
           }
-        }
+        });
 
         // check if overflowed items would fit if the moreButton were not visible
         const overflowedWidth = overflowItemsIdx.reduce(
@@ -195,11 +207,17 @@
           maxWidth -= removedDividerWidth;
         }
 
-        maxWidth = Math.ceil(maxWidth);
-        this.overflowItems = overflowItemsIdx.map(idx => this.items[idx]);
+        this.overflowItems = overflowItemsIdx.map((idx) => this.items[idx]);
         this.isMoreButtonVisible = overflowItemsIdx.length > 0;
-        list.style.maxWidth = `${maxWidth}px`;
+        list.style.maxWidth = `${Math.ceil(maxWidth)}px`;
         list.style.maxHeight = `${maxHeight}px`;
+
+        this.setVisibleItems(directionIndexes, overflowItemsIdx);
+      },
+      setVisibleItems(directionIndexes, overflowItemsIdx) {
+        // Set the visible items based on overflow logic
+        const visibleIndexes = directionIndexes.filter((idx) => !overflowItemsIdx.includes(idx));
+        this.visibleItems = visibleIndexes.map((idx) => this.items[idx]);
       },
       /**
        * Fixes the visibility of the dividers that are shown and hidden when the list overflows.
@@ -276,5 +294,8 @@
   .more-button-wrapper {
     visibility: hidden;
   }
+  .more-button-wrapper.start-button {
+    order: -1; /* Puts the more button at the start */
+  }
 
-</style>
+</style>
\ No newline at end of file