diff --git a/.github/actions/download-locales/action.yml b/.github/actions/download-locales/action.yml
index db73d7b681ad..413566dad881 100644
--- a/.github/actions/download-locales/action.yml
+++ b/.github/actions/download-locales/action.yml
@@ -11,7 +11,7 @@ runs:
   using: composite
   steps:
     - name: Download eo-UY
-      uses: crowdin/github-action@v1.12.0
+      uses: crowdin/github-action@v1.19.0
       with:
         download_language: eo
         config: crowdin.yml
@@ -21,7 +21,7 @@ runs:
         export_only_approved: false
         crowdin_branch_name: ${{ inputs.crowdin-branch }}
     - name: Download zh-CN
-      uses: crowdin/github-action@v1.12.0
+      uses: crowdin/github-action@v1.19.0
       with:
         download_language: zh-CN
         config: crowdin.yml
diff --git a/.github/actions/nightly-release/action.yml b/.github/actions/nightly-release/action.yml
index a36f3e3289b3..fe8d525545f9 100644
--- a/.github/actions/nightly-release/action.yml
+++ b/.github/actions/nightly-release/action.yml
@@ -30,7 +30,7 @@ runs:
         git config --global user.email "actions@github.com"
         git config --global user.name "GitHub Actions"
       shell: bash
-    - uses: actions/checkout@v2
+    - uses: actions/checkout@v4
       with:
         repository: ${{ inputs.checkout-repo }}
         ref: ${{ inputs.checkout-ref }}
diff --git a/.github/actions/yarn-install/action.yml b/.github/actions/yarn-install/action.yml
index aff639a366fb..4148990647f4 100644
--- a/.github/actions/yarn-install/action.yml
+++ b/.github/actions/yarn-install/action.yml
@@ -4,7 +4,7 @@ description: Restore node_modules and cache, then run yarn install
 runs:
   using: composite
   steps:
-    - uses: actions/cache@v2
+    - uses: actions/cache@v4
       with:
         path: |
           node_modules
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index afe39e488031..ed13ae181050 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -30,7 +30,7 @@ jobs:
     if: needs.pre_job.outputs.should_skip != 'true'
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v2
+      - uses: actions/checkout@v4
       - uses: ./.github/actions/yarn-install
       - run: yarn build vuetify
       - uses: ./.github/actions/upload-artifact
@@ -50,7 +50,7 @@ jobs:
       matrix:
         scopes: ['--scope vuetify --scope @vuetify/api-generator', '--scope vuetifyjs.com']
     steps:
-      - uses: actions/checkout@v2
+      - uses: actions/checkout@v4
       - uses: ./.github/actions/download-artifact
         with:
           name: vuetify-dist
@@ -65,11 +65,11 @@ jobs:
     if: needs.pre_job.outputs.should_skip != 'true'
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v2
+      - uses: actions/checkout@v4
       - uses: ./.github/actions/yarn-install
       - run: yarn run test:coverage -i
         working-directory: ./packages/vuetify
-      - uses: codecov/codecov-action@v1
+      - uses: codecov/codecov-action@v4
 
   test-cypress:
     name: Test (Cypress)
@@ -77,7 +77,7 @@ jobs:
     if: needs.pre_job.outputs.should_skip != 'true'
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v2
+      - uses: actions/checkout@v4
       - uses: ./.github/actions/yarn-install
       - run: yarn cy:run --record --parallel --ci-build-id $GITHUB_RUN_ID
         if: ${{ !startswith(github.ref, 'refs/tags/v') && github.repository_owner == 'vuetifyjs' }}
@@ -87,7 +87,7 @@ jobs:
       - run: yarn cy:run
         if: ${{ !startswith(github.ref, 'refs/tags/v') && github.repository_owner != 'vuetifyjs' }}
         working-directory: ./packages/vuetify
-      - uses: actions/upload-artifact@v2
+      - uses: actions/upload-artifact@v3
         if: failure()
         with:
           name: cypress-screenshots
@@ -99,7 +99,7 @@ jobs:
     runs-on: ubuntu-latest
     if: github.event_name == 'push' && startswith(github.ref, 'refs/tags/v') && github.repository_owner == 'vuetifyjs'
     steps:
-      - uses: actions/checkout@v2
+      - uses: actions/checkout@v4
         with:
           fetch-depth: 0
       - uses: ./.github/actions/download-artifact
@@ -125,7 +125,7 @@ jobs:
     if: needs.pre_job.outputs.should_skip != 'true' && github.event_name == 'push' && github.repository_owner == 'vuetifyjs' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/next')
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v2
+      - uses: actions/checkout@v4
       - uses: ./.github/actions/download-artifact
         with:
           name: vuetify-dist
@@ -156,7 +156,7 @@ jobs:
     runs-on: ubuntu-latest
     if: github.event_name == 'push' && github.repository_owner == 'vuetifyjs' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/next')
     steps:
-      - uses: actions/checkout@v2
+      - uses: actions/checkout@v4
       - uses: ./.github/actions/download-artifact
         with:
           name: docs-dist
diff --git a/.github/workflows/crowdin-uploads.yml b/.github/workflows/crowdin-uploads.yml
index 45d851527f9a..01e839d9f18e 100644
--- a/.github/workflows/crowdin-uploads.yml
+++ b/.github/workflows/crowdin-uploads.yml
@@ -26,10 +26,10 @@ jobs:
     steps:
 
     - name: Checkout
-      uses: actions/checkout@v2
+      uses: actions/checkout@v4
 
     - name: Upload
-      uses: crowdin/github-action@v1.12.0
+      uses: crowdin/github-action@v1.19.0
       with:
         config: crowdin.yml
         crowdin_branch_name: ${{ env.CROWDIN_BRANCH }}
diff --git a/.github/workflows/nightly-pr.yml b/.github/workflows/nightly-pr.yml
index a66ff7b5631e..b55f1652a72b 100644
--- a/.github/workflows/nightly-pr.yml
+++ b/.github/workflows/nightly-pr.yml
@@ -12,8 +12,8 @@ jobs:
     runs-on: ubuntu-latest
     if: ${{ github.repository_owner == 'vuetifyjs' }}
     steps:
-      - uses: actions/checkout@v2
-      - uses: actions/github-script@v6
+      - uses: actions/checkout@v4
+      - uses: actions/github-script@v7
         with:
           script: |
             const pr = await github.rest.pulls.get({
@@ -32,8 +32,8 @@ jobs:
           release-id: pr-${{ github.event.inputs.pr }}.${{ env.SHORT_SHA }}
           npm-tag: pr
           npm-token: ${{ secrets.NPM_TOKEN }}
-      - uses: actions/checkout@v2
-      - uses: actions/github-script@v6
+      - uses: actions/checkout@v4
+      - uses: actions/github-script@v7
         with:
           script: |
             const fullVersion = process.env.FULL_VERSION
diff --git a/.github/workflows/nightly-schedule.yml b/.github/workflows/nightly-schedule.yml
index 1a796988b79f..2429f338b08b 100644
--- a/.github/workflows/nightly-schedule.yml
+++ b/.github/workflows/nightly-schedule.yml
@@ -25,7 +25,7 @@ jobs:
           - branch: 'v2-dev'
             tag: 'v2-dev'
     steps:
-      - uses: actions/checkout@v2
+      - uses: actions/checkout@v4
         with:
           ref: ${{ matrix.branch }}
           fetch-depth: 0
@@ -45,14 +45,14 @@ jobs:
           release-id: ${{ matrix.branch }}.${{ env.RELEASE_ID }}
           npm-tag: ${{ matrix.tag }}
           npm-token: ${{ secrets.NPM_TOKEN }}
-      - uses: actions/checkout@v2
+      - uses: actions/checkout@v4
 
   percy:
     name: Visual regression tests
     runs-on: ubuntu-latest
     if: ${{ github.repository_owner == 'vuetifyjs' }}
     steps:
-      - uses: actions/checkout@v2
+      - uses: actions/checkout@v4
         with:
           ref: master
           fetch-depth: 0
@@ -73,7 +73,7 @@ jobs:
           PERCY_BRANCH: master
           PERCY_TARGET_BRANCH: master
           PERCY_COMMIT: ${{ env.COMMIT }}
-      - uses: actions/upload-artifact@v2
+      - uses: actions/upload-artifact@v3
         if: failure()
         with:
           name: cypress-screenshots
diff --git a/.github/workflows/triage.yml b/.github/workflows/triage.yml
index 78345fd0f66c..6b25c9fe022e 100644
--- a/.github/workflows/triage.yml
+++ b/.github/workflows/triage.yml
@@ -7,7 +7,7 @@ jobs:
   triage:
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v2
+      - uses: actions/checkout@v4
       - uses: vuetifyjs/triage-action@master
         with:
           token: ${{ secrets.GITHUB_TOKEN }}
diff --git a/lerna.json b/lerna.json
index d8a3a31e5d6a..d7e638719ca2 100644
--- a/lerna.json
+++ b/lerna.json
@@ -13,6 +13,6 @@
     }
   },
   "npmClient": "yarn",
-  "version": "3.5.9",
+  "version": "3.5.11",
   "useWorkspaces": true
 }
diff --git a/packages/api-generator/package.json b/packages/api-generator/package.json
index 5c60ea205b5a..b08a9bcc089b 100755
--- a/packages/api-generator/package.json
+++ b/packages/api-generator/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@vuetify/api-generator",
-  "version": "3.5.9",
+  "version": "3.5.11",
   "private": true,
   "description": "",
   "scripts": {
@@ -17,7 +17,7 @@
     "ts-morph": "^20.0.0",
     "tsx": "^4.6.2",
     "vue": "^3.4.19",
-    "vuetify": "^3.5.9"
+    "vuetify": "^3.5.11"
   },
   "devDependencies": {
     "@types/stringify-object": "^4.0.5"
diff --git a/packages/docs/auto-imports.d.ts b/packages/docs/auto-imports.d.ts
index 3bc411259825..7e625ea903aa 100644
--- a/packages/docs/auto-imports.d.ts
+++ b/packages/docs/auto-imports.d.ts
@@ -75,6 +75,7 @@ declare global {
   const useOneStore: typeof import('@vuetify/one')['useOneStore']
   const usePinsStore: typeof import('./src/stores/pins')['usePinsStore']
   const usePlayground: typeof import('./src/composables/playground')['usePlayground']
+  const useProductsStore: typeof import('@vuetify/one')['useProductsStore']
   const usePromotionsStore: typeof import('./src/stores/promotions')['usePromotionsStore']
   const useReleasesStore: typeof import('./src/stores/releases')['useReleasesStore']
   const useRoute: typeof import('vue-router')['useRoute']
@@ -164,6 +165,7 @@ declare module 'vue' {
     readonly useOneStore: UnwrapRef<typeof import('@vuetify/one')['useOneStore']>
     readonly usePinsStore: UnwrapRef<typeof import('./src/stores/pins')['usePinsStore']>
     readonly usePlayground: UnwrapRef<typeof import('./src/composables/playground')['usePlayground']>
+    readonly useProductsStore: UnwrapRef<typeof import('@vuetify/one')['useProductsStore']>
     readonly usePromotionsStore: UnwrapRef<typeof import('./src/stores/promotions')['usePromotionsStore']>
     readonly useReleasesStore: UnwrapRef<typeof import('./src/stores/releases')['useReleasesStore']>
     readonly useRoute: UnwrapRef<typeof import('vue-router')['useRoute']>
@@ -252,6 +254,7 @@ declare module '@vue/runtime-core' {
     readonly useOneStore: UnwrapRef<typeof import('@vuetify/one')['useOneStore']>
     readonly usePinsStore: UnwrapRef<typeof import('./src/stores/pins')['usePinsStore']>
     readonly usePlayground: UnwrapRef<typeof import('./src/composables/playground')['usePlayground']>
+    readonly useProductsStore: UnwrapRef<typeof import('@vuetify/one')['useProductsStore']>
     readonly usePromotionsStore: UnwrapRef<typeof import('./src/stores/promotions')['usePromotionsStore']>
     readonly useReleasesStore: UnwrapRef<typeof import('./src/stores/releases')['useReleasesStore']>
     readonly useRoute: UnwrapRef<typeof import('vue-router')['useRoute']>
diff --git a/packages/docs/components.d.ts b/packages/docs/components.d.ts
index ca7d4e752315..c53f1629ae37 100644
--- a/packages/docs/components.d.ts
+++ b/packages/docs/components.d.ts
@@ -40,6 +40,7 @@ declare module 'vue' {
     AppBarThemeToggle: typeof import('./src/components/app/bar/ThemeToggle.vue')['default']
     AppBtn: typeof import('./src/components/app/Btn.vue')['default']
     AppCaption: typeof import('./src/components/app/Caption.vue')['default']
+    AppCommitBtn: typeof import('./src/components/app/CommitBtn.vue')['default']
     AppDivider: typeof import('./src/components/app/Divider.vue')['default']
     AppDrawerAppend: typeof import('./src/components/app/drawer/Append.vue')['default']
     AppDrawerDrawer: typeof import('./src/components/app/drawer/Drawer.vue')['default']
@@ -86,6 +87,7 @@ declare module 'vue' {
     AppToc: typeof import('./src/components/app/Toc.vue')['default']
     AppTooltipBtn: typeof import('./src/components/app/TooltipBtn.vue')['default']
     AppV2Banner: typeof import('./src/components/app/V2Banner.vue')['default']
+    AppVersionBtn: typeof import('./src/components/app/VersionBtn.vue')['default']
     AppVerticalDivider: typeof import('./src/components/app/VerticalDivider.vue')['default']
     Backmatter: typeof import('./src/components/Backmatter.vue')['default']
     ComponentsListItem: typeof import('./src/components/components/ListItem.vue')['default']
@@ -97,6 +99,7 @@ declare module 'vue' {
     DocMadeWithVueAttribution: typeof import('./src/components/doc/MadeWithVueAttribution.vue')['default']
     DocMadeWithVuetifyGallery: typeof import('./src/components/doc/MadeWithVuetifyGallery.vue')['default']
     DocMadeWithVuetifyLink: typeof import('./src/components/doc/MadeWithVuetifyLink.vue')['default']
+    DocPremiumThemesGallery: typeof import('./src/components/doc/PremiumThemesGallery.vue')['default']
     DocReadyForMore: typeof import('./src/components/doc/ReadyForMore.vue')['default']
     DocRelatedPage: typeof import('./src/components/doc/RelatedPage.vue')['default']
     DocRelatedPages: typeof import('./src/components/doc/RelatedPages.vue')['default']
diff --git a/packages/docs/package.json b/packages/docs/package.json
index 07d0b92fbd16..7b6a5370bb2e 100644
--- a/packages/docs/package.json
+++ b/packages/docs/package.json
@@ -3,7 +3,7 @@
   "description": "A Vue.js project",
   "private": true,
   "author": "John Leider <john@vuetifyjs.com>",
-  "version": "3.5.9",
+  "version": "3.5.11",
   "repository": {
     "type": "git",
     "url": "git+https://github.com/vuetifyjs/vuetify.git",
@@ -23,7 +23,7 @@
     "@cosmicjs/sdk": "^1.0.11",
     "@vuelidate/core": "^2.0.3",
     "@vuelidate/validators": "^2.0.4",
-    "@vuetify/one": "^1.2.4",
+    "@vuetify/one": "^1.5.0",
     "algoliasearch": "^4.20.0",
     "fflate": "^0.8.1",
     "isomorphic-fetch": "^3.0.0",
@@ -38,7 +38,7 @@
     "vue-i18n": "^9.7.1",
     "vue-instantsearch": "^4.12.1",
     "vue-prism-component": "^2.0.0",
-    "vuetify": "^3.5.9"
+    "vuetify": "^3.5.11"
   },
   "devDependencies": {
     "@emailjs/browser": "^3.11.0",
@@ -50,7 +50,7 @@
     "@vitejs/plugin-basic-ssl": "^1.0.2",
     "@vitejs/plugin-vue": "^4.5.2",
     "@vue/compiler-sfc": "^3.4.19",
-    "@vuetify/api-generator": "^3.5.9",
+    "@vuetify/api-generator": "^3.5.11",
     "ajv": "^8.12.0",
     "async-es": "^3.2.5",
     "date-fns": "^2.30.0",
diff --git a/packages/docs/src/components/Backmatter.vue b/packages/docs/src/components/Backmatter.vue
index ba43212da6eb..d0dd79f1eb87 100644
--- a/packages/docs/src/components/Backmatter.vue
+++ b/packages/docs/src/components/Backmatter.vue
@@ -11,8 +11,6 @@
 
     <DocUpNext />
 
-    <PromotedPromoted />
-
     <DocContribute />
   </section>
 </template>
diff --git a/packages/docs/src/components/app/CommitBtn.vue b/packages/docs/src/components/app/CommitBtn.vue
new file mode 100644
index 000000000000..f5b18197d131
--- /dev/null
+++ b/packages/docs/src/components/app/CommitBtn.vue
@@ -0,0 +1,18 @@
+<template>
+  <v-btn
+    v-if="commits.latest"
+    :href="`https://github.com/vuetifyjs/vuetify/commit/${commits.latest?.sha}`"
+    :text="commits.latest?.sha.slice(0, 7)"
+    class="text-caption"
+    prepend-icon="mdi-source-commit"
+    rel="noopener noreferrer"
+    size="small"
+    target="_blank"
+    variant="text"
+    slim
+  />
+</template>
+
+<script lang="ts" setup>
+  const commits = useCommitsStore()
+</script>
diff --git a/packages/docs/src/components/app/VersionBtn.vue b/packages/docs/src/components/app/VersionBtn.vue
new file mode 100644
index 000000000000..36ed352adc62
--- /dev/null
+++ b/packages/docs/src/components/app/VersionBtn.vue
@@ -0,0 +1,16 @@
+<template>
+  <v-btn
+    :text="version"
+    :to="rpath(`/getting-started/release-notes/?version=v${version}`)"
+    class="text-caption"
+    prepend-icon="mdi-tag-outline"
+    size="small"
+    variant="text"
+    slim
+  />
+</template>
+
+<script lang="ts" setup>
+  // Utilities
+  import { version } from 'vuetify'
+</script>
diff --git a/packages/docs/src/components/app/drawer/Append.vue b/packages/docs/src/components/app/drawer/Append.vue
index 75cceb27367c..328c8e881b59 100644
--- a/packages/docs/src/components/app/drawer/Append.vue
+++ b/packages/docs/src/components/app/drawer/Append.vue
@@ -5,36 +5,13 @@
     <AppDrawerDrawerToggleRail v-if="auth.isSubscriber" class="me-2" />
 
     <div class="d-flex ms-auto overflow-hidden">
-      <v-btn
-        v-if="commits.latest"
-        :href="`https://github.com/vuetifyjs/vuetify/commit/${commits.latest?.sha}`"
-        :text="commits.latest?.sha.slice(0, 7)"
-        class="text-caption me-2"
-        prepend-icon="mdi-source-commit"
-        rel="noopener noreferrer"
-        size="small"
-        target="_blank"
-        variant="text"
-        slim
-      />
+      <AppCommitBtn class="me-2" />
 
-      <v-btn
-        :text="version"
-        :to="rpath(`/getting-started/release-notes/?version=v${version}`)"
-        class="text-caption"
-        prepend-icon="mdi-tag-outline"
-        size="small"
-        variant="text"
-        slim
-      />
+      <AppVersionBtn />
     </div>
   </div>
 </template>
 
 <script setup lang="ts">
-  // Utilities
-  import { version } from 'vuetify'
-
   const auth = useAuthStore()
-  const commits = useCommitsStore()
 </script>
diff --git a/packages/docs/src/components/doc/MadeWithVuetifyGallery.vue b/packages/docs/src/components/doc/MadeWithVuetifyGallery.vue
index be75beb13996..2d5ad1563f5d 100644
--- a/packages/docs/src/components/doc/MadeWithVuetifyGallery.vue
+++ b/packages/docs/src/components/doc/MadeWithVuetifyGallery.vue
@@ -11,9 +11,9 @@
         cols="12"
         md="4"
       >
-        <v-skeleton-loader height="180" />
+        <v-skeleton-loader class="rounded-b-0" height="180" />
 
-        <v-skeleton-loader type="text" />
+        <v-skeleton-loader class="rounded-t-0" type="text" />
       </v-col>
     </v-row>
 
@@ -42,9 +42,10 @@
                 :name="project.raw.title"
                 :src="project.raw.image"
                 :title="project.raw.title"
-                class="border"
-                height="180"
-                min-height="180"
+                height="230"
+                max-height="230"
+                min-height="230"
+                cover
                 eager
               />
             </a>
@@ -79,7 +80,7 @@
   const store = useMadeWithVuetifyStore()
 
   const items = computed(() => {
-    return shuffle(store.items)
+    return shuffle(store.items.slice())
   })
 
   function shuffle (array) {
diff --git a/packages/docs/src/components/doc/MadeWithVuetifyLink.vue b/packages/docs/src/components/doc/MadeWithVuetifyLink.vue
index 8f6af981d5b5..111db0ebb378 100644
--- a/packages/docs/src/components/doc/MadeWithVuetifyLink.vue
+++ b/packages/docs/src/components/doc/MadeWithVuetifyLink.vue
@@ -3,6 +3,7 @@
     :aria-label="t('see-more-projects')"
     :size="size"
     :to="rpath('/resources/made-with-vuetify/')"
+    append-icon="mdi-page-next"
     color="primary"
     variant="outlined"
     @click="onClick"
diff --git a/packages/docs/src/components/doc/PremiumThemesGallery.vue b/packages/docs/src/components/doc/PremiumThemesGallery.vue
new file mode 100644
index 000000000000..2964c122969e
--- /dev/null
+++ b/packages/docs/src/components/doc/PremiumThemesGallery.vue
@@ -0,0 +1,90 @@
+<template>
+  <v-sheet
+    class="mx-auto text-center pa-3 mb-4"
+    color="transparent"
+    max-width="900"
+  >
+    <v-row v-if="!items.length">
+      <v-col
+        v-for="n in 9"
+        :key="n"
+        cols="12"
+        md="4"
+      >
+        <v-skeleton-loader class="rounded-b-0" height="180" />
+
+        <v-skeleton-loader class="rounded-t-0" type="text" />
+      </v-col>
+    </v-row>
+
+    <v-data-iterator
+      v-else
+      :items="items"
+      :items-per-page="itemsPerPage"
+      :page="page"
+    >
+      <template #default="{ items: _items }">
+        <v-row style="min-height: 750px;">
+          <v-col
+            v-for="product in _items"
+            :key="product.raw.id"
+            cols="12"
+            sm="4"
+          >
+            <a
+              :href="`https://store.vuetifyjs.com/products/${product.raw.handle}`"
+              class="d-block text-decoration-none"
+              rel="noopener noreferrer"
+              style="min-height: 205px;"
+              target="_blank"
+            >
+              <DocThemeCard
+                :product="{
+                  title: product.raw.title,
+                  src: product.raw.image,
+                }"
+                class="text-center"
+              />
+            </a>
+          </v-col>
+        </v-row>
+      </template>
+    </v-data-iterator>
+  </v-sheet>
+
+  <v-btn
+    append-icon="mdi-open-in-new"
+    aria-label="See More Templates"
+    color="primary"
+    href="https://store.vuetifyjs.com"
+    rel="noopener noreferrer"
+    size="large"
+    target="_blank"
+    variant="outlined"
+  >
+    <span class="text-capitalize font-weight-regular">
+      See More Templates
+    </span>
+  </v-btn>
+</template>
+
+<script setup>
+  defineProps({
+    itemsPerPage: {
+      type: [Number, String],
+      default: 9,
+    },
+  })
+
+  const page = ref(1)
+
+  const products = useProductsStore()
+
+  const items = shallowRef([])
+
+  onMounted(async () => {
+    await products.index()
+
+    items.value = products.randomize(products.themes)
+  })
+</script>
diff --git a/packages/docs/src/components/doc/Releases.vue b/packages/docs/src/components/doc/Releases.vue
index 3093c9d98099..3709c08558b3 100644
--- a/packages/docs/src/components/doc/Releases.vue
+++ b/packages/docs/src/components/doc/Releases.vue
@@ -11,6 +11,8 @@
       item-title="name"
       label="Select Release Version"
       prepend-inner-icon="mdi-text-box-search-outline"
+      rounded="b-0"
+      variant="solo-filled"
       hide-details
       hide-no-data
       persistent-placeholder
@@ -73,7 +75,7 @@
     >
       <div
         v-if="model?.author"
-        class="d-flex align-center justify-space-between pa-4 bg-grey-lighten-5"
+        class="d-flex align-center justify-space-between pa-4 bg-surface-light border-y"
       >
         <div class="d-flex align-center text-caption">
           <i18n-t v-if="publishedOn" keypath="published" scope="global">
diff --git a/packages/docs/src/components/doc/ThemeCard.vue b/packages/docs/src/components/doc/ThemeCard.vue
index 005d2b146bd6..fd91029b9200 100644
--- a/packages/docs/src/components/doc/ThemeCard.vue
+++ b/packages/docs/src/components/doc/ThemeCard.vue
@@ -14,7 +14,7 @@
       min-height="230"
       cover
     >
-      <figcaption class="d-flex text-subtitle-2 align-center text-capitalize mt-3">
+      <figcaption class="d-flex text-subtitle-2 align-center justify-center text-capitalize mt-3">
         <span v-text="product.title" />
 
         <v-chip
@@ -27,7 +27,7 @@
         />
 
         <span
-          v-else
+          v-else-if="product.price"
           class="ms-auto text-subtitle-1 font-weight-bold"
           v-text="`$${product.price}`"
         />
diff --git a/packages/docs/src/components/examples/UsageExample.vue b/packages/docs/src/components/examples/UsageExample.vue
index cd2a6d6debc6..a81c1ab9366c 100644
--- a/packages/docs/src/components/examples/UsageExample.vue
+++ b/packages/docs/src/components/examples/UsageExample.vue
@@ -164,7 +164,7 @@
     {
       name: 'template',
       language: 'html',
-      content: `<template>\n  <v-app>\n    <v-container>\n      ${props.code.replaceAll('\n', '\n      ')}\n    </v-container>\n  </v-app>\n</template>`,
+      content: `<template>\n  <v-app>\n    <v-container>\n      ${props.code.replaceAll('\n', '\n      ')}\n    </v-container>\n  </v-app>\n</template>\n${props.script}`,
     },
   ]))
 </script>
diff --git a/packages/docs/src/components/home/Entry.vue b/packages/docs/src/components/home/Entry.vue
index 60b17ce3b3c0..80e581613dd6 100644
--- a/packages/docs/src/components/home/Entry.vue
+++ b/packages/docs/src/components/home/Entry.vue
@@ -21,42 +21,74 @@
 
         <br>
 
-        <v-hover>
-          <template #default="{ isHovering, props }">
+        <v-row :justify="mdAndDown ? 'center' : undefined">
+          <v-col cols="auto">
+            <v-hover>
+              <template #default="{ isHovering, props }">
+                <v-sheet
+                  class="px-2 py-2 d-inline-flex align-center text-mono text-body-2 text-no-wrap"
+                  color="surface"
+                  width="215"
+                  border
+                  rounded
+                  v-bind="props"
+                >
+                  <v-icon
+                    class="me-1"
+                    color="medium-emphasis"
+                    icon="mdi-chevron-right"
+                    size="16"
+                  />
+
+                  {{ randomPackage }} create
+
+                  <span class="text-primary font-weight-medium ms-2">
+                    vuetify
+                  </span>
+
+                  <v-icon
+                    :icon="isCopying ? 'mdi-check' : 'mdi-clipboard-text-outline'"
+                    :style="{
+                      opacity: isHovering || isCopying ? 1 : 0,
+                    }"
+                    class="ms-auto"
+                    color="medium-emphasis"
+                    size="17"
+                    @click="copy"
+                  />
+                </v-sheet>
+              </template>
+            </v-hover>
+          </v-col>
+
+          <v-col cols="auto">
             <v-sheet
-              class="px-2 py-2 d-inline-flex align-center text-mono text-body-2 text-no-wrap"
+              class="pa-1 ps-3 d-inline-flex align-center justify-space-between text-caption"
               color="surface"
               width="215"
               border
               rounded
-              v-bind="props"
             >
-              <v-icon
-                class="me-1"
-                color="medium-emphasis"
-                icon="mdi-chevron-right"
-                size="16"
-              />
-
-              yarn create
-
-              <span class="text-primary font-weight-medium ms-2">
-                vuetify
-              </span>
-
-              <v-icon
-                :icon="isCopying ? 'mdi-check' : 'mdi-clipboard-text-outline'"
-                :style="{
-                  opacity: isHovering || isCopying ? 1 : 0,
-                }"
-                class="ms-auto"
-                color="medium-emphasis"
-                size="17"
-                @click="copy"
-              />
+              <span class="me-2">Latest Commit:</span>
+
+              <AppCommitBtn />
             </v-sheet>
-          </template>
-        </v-hover>
+          </v-col>
+
+          <v-col cols="auto">
+            <v-sheet
+              class="pa-1 ps-3 d-inline-flex align-center justify-space-between text-caption"
+              color="surface"
+              width="215"
+              border
+              rounded
+            >
+              <span class="me-2">Latest Release:</span>
+
+              <AppVersionBtn />
+            </v-sheet>
+          </v-col>
+        </v-row>
       </v-col>
     </v-row>
   </v-container>
@@ -65,6 +97,10 @@
 <script setup>
   const isCopying = shallowRef(false)
 
+  const { mdAndDown } = useDisplay()
+  const packages = ['npm', 'yarn', 'pnpm', 'bun']
+  const randomPackage = packages[Math.floor(Math.random() * packages.length)]
+
   function copy () {
     isCopying.value = true
 
diff --git a/packages/docs/src/components/home/Footer.vue b/packages/docs/src/components/home/Footer.vue
index 10256196ec97..6701cceb749a 100644
--- a/packages/docs/src/components/home/Footer.vue
+++ b/packages/docs/src/components/home/Footer.vue
@@ -2,16 +2,15 @@
   <v-footer
     id="footer"
     class="d-block py-6"
-    color="surface-bright"
+    color="surface-light"
   >
     <v-container class="text-center">
       <v-row>
         <v-col cols="12">
           <v-img
-            :src="`https://cdn.vuetifyjs.com/docs/images/logos/vuetify-logo-${theme.name.value}-slim.svg`"
+            :src="`https://cdn.vuetifyjs.com/docs/images/logos/vuetify-logo-${theme.current.value.dark ? 'dark' : 'light'}-slim.svg`"
             class="mx-auto"
             height="64"
-            width="64"
             contain
           />
         </v-col>
diff --git a/packages/docs/src/components/home/Logo.vue b/packages/docs/src/components/home/Logo.vue
index 6ce261ac14cc..d567d832d00e 100644
--- a/packages/docs/src/components/home/Logo.vue
+++ b/packages/docs/src/components/home/Logo.vue
@@ -17,6 +17,6 @@
   const theme = useTheme()
 
   const logo = computed(() => {
-    return `vuetify-logo-${theme.name.value}-atom.svg`
+    return `vuetify-logo-${theme.current.value.dark ? 'dark' : 'light'}-atom.svg`
   })
 </script>
diff --git a/packages/docs/src/components/home/Sponsors.vue b/packages/docs/src/components/home/Sponsors.vue
index 76aa251d6ce9..0b4c436211b4 100644
--- a/packages/docs/src/components/home/Sponsors.vue
+++ b/packages/docs/src/components/home/Sponsors.vue
@@ -30,7 +30,7 @@
     <br>
     <br>
 
-    <SponsorLink size="large" />
+    <SponsorLink append-icon="mdi-page-next" size="large" />
   </v-sheet>
 </template>
 
diff --git a/packages/docs/src/data/nav.json b/packages/docs/src/data/nav.json
index 08d65dd87aa9..4c10ab2a81ca 100644
--- a/packages/docs/src/data/nav.json
+++ b/packages/docs/src/data/nav.json
@@ -231,6 +231,10 @@
         "title": "floating-action-buttons",
         "subfolder": "components"
       },
+      {
+        "title": "number-inputs",
+        "subfolder": "components"
+      },
       {
         "title": "sparklines",
         "subfolder": "components"
diff --git a/packages/docs/src/examples/v-data-iterator/usage.vue b/packages/docs/src/examples/v-data-iterator/usage.vue
index d76504918d5b..14f157e581b7 100644
--- a/packages/docs/src/examples/v-data-iterator/usage.vue
+++ b/packages/docs/src/examples/v-data-iterator/usage.vue
@@ -71,14 +71,14 @@
   })
 
   const script = computed(() => {
-    return `export default {
-  data: () => ({
-    page: 1,
-    items: Array.from({ length: 15 }, (k, v) => ({
-      title: 'Item ' + v + 1,
-      text: 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Commodi, ratione debitis quis est labore voluptatibus! Eaque cupiditate minima, at placeat totam, magni doloremque veniam neque porro libero rerum unde voluptatem!',
-    })),
-  }),
-}`
+    return `<script setup>
+  import { ref } from 'vue'
+
+  const page = ref(1)
+  const items = Array.from({ length: 15 }, (k, v) => ({
+    title: 'Item ' + v + 1,
+    text: 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Commodi, ratione debitis quis est labore voluptatibus! Eaque cupiditate minima, at placeat totam, magni doloremque veniam neque porro libero rerum unde voluptatem!',
+  }))
+<` + '/script>'
   })
 </script>
diff --git a/packages/docs/src/examples/v-data-table/usage.vue b/packages/docs/src/examples/v-data-table/usage.vue
index 0d345af90d93..3a67557dbbcd 100644
--- a/packages/docs/src/examples/v-data-table/usage.vue
+++ b/packages/docs/src/examples/v-data-table/usage.vue
@@ -4,6 +4,7 @@
     :code="code"
     :name="name"
     :options="options"
+    :script="script"
   >
     <div>
       <v-data-table
@@ -104,6 +105,6 @@
   })
 
   const code = computed(() => {
-    return `<template>\n  <v-data-table${propsToString(props.value, 2)}></v-data-table>\n</template>\n\n${script.value}`
+    return `<v-data-table${propsToString(props.value, 2)}></v-data-table>`
   })
 </script>
diff --git a/packages/docs/src/examples/v-infinite-scroll/usage.vue b/packages/docs/src/examples/v-infinite-scroll/usage.vue
index d6256d067a1c..9265fa96f83f 100644
--- a/packages/docs/src/examples/v-infinite-scroll/usage.vue
+++ b/packages/docs/src/examples/v-infinite-scroll/usage.vue
@@ -57,7 +57,7 @@
     return `
   <template v-for="(item, index) in items" :key="item">
     <div :class="['pa-2', index % 2 === 0 ? 'bg-grey-lighten-2' : '']">
-      Item #{{ item }}
+      Item number #{{ item }}
     </div>
   </template>
 `
@@ -68,28 +68,26 @@
   })
 
   const script = computed(() => {
-    return `export default {
-  data: () => ({
-    items: [],
-  }),
+    return `<script setup>
+  import { ref } from 'vue'
 
-  methods: {
-    async api () {
-      return new Promise(resolve => {
-        setTimeout(() => {
-          resolve(Array.from({ length: 10 }, (k, v) => v + this.items.at(-1) + 1))
-        }, 1000)
-      })
-    },
-    async load ({ done }) {
-      // Perform API call
-      const res = await this.api()
+  const items = ref(Array.from({ length: 30 }, (k, v) => v + 1))
+
+  async function api () {
+    return new Promise(resolve => {
+      setTimeout(() => {
+        resolve(Array.from({ length: 10 }, (k, v) => v + items.value.at(-1) + 1))
+      }, 1000)
+    })
+  }
+  async function load ({ done }) {
+    // Perform API call
+    const res = await api()
 
-      this.items.push(...res)
+    items.value.push(...res)
 
-      done('ok')
-    },
-  },
-}`
+    done('ok')
+  }
+<` + '/script>'
   })
 </script>
diff --git a/packages/docs/src/examples/v-number-input/prop-control-variant.vue b/packages/docs/src/examples/v-number-input/prop-control-variant.vue
new file mode 100644
index 000000000000..7f5c7d49e029
--- /dev/null
+++ b/packages/docs/src/examples/v-number-input/prop-control-variant.vue
@@ -0,0 +1,23 @@
+<template>
+  <v-container>
+    <v-row>
+      <v-col cols="12" md="4" sm="4">
+        <h5>Default</h5>
+
+        <v-number-input control-variant="default"></v-number-input>
+      </v-col>
+
+      <v-col cols="12" md="4" sm="4">
+        <h5>Stacked</h5>
+
+        <v-number-input control-variant="stacked"></v-number-input>
+      </v-col>
+
+      <v-col cols="12" md="4" sm="4">
+        <h5>Split</h5>
+
+        <v-number-input control-variant="split"></v-number-input>
+      </v-col>
+    </v-row>
+  </v-container>
+</template>
diff --git a/packages/docs/src/examples/v-number-input/prop-hide-input.vue b/packages/docs/src/examples/v-number-input/prop-hide-input.vue
new file mode 100644
index 000000000000..954ea1bc9b26
--- /dev/null
+++ b/packages/docs/src/examples/v-number-input/prop-hide-input.vue
@@ -0,0 +1,9 @@
+<template>
+  <v-container>
+    <v-row justify="center">
+      <v-col cols="auto">
+        <v-number-input hide-input></v-number-input>
+      </v-col>
+    </v-row>
+  </v-container>
+</template>
diff --git a/packages/docs/src/examples/v-number-input/prop-inset.vue b/packages/docs/src/examples/v-number-input/prop-inset.vue
new file mode 100644
index 000000000000..d40c6caecdd7
--- /dev/null
+++ b/packages/docs/src/examples/v-number-input/prop-inset.vue
@@ -0,0 +1,41 @@
+<template>
+  <v-container>
+    <v-row>
+      <v-col cols="12" sm="6">
+        <h5>Default</h5>
+
+        <v-number-input
+          control-variant="default"
+          inset
+        ></v-number-input>
+      </v-col>
+
+      <v-col cols="12" sm="6">
+        <h5>Stacked</h5>
+
+        <v-number-input
+          control-variant="stacked"
+          inset
+        ></v-number-input>
+      </v-col>
+
+      <v-col cols="12" sm="6">
+        <h5>Split</h5>
+
+        <v-number-input
+          control-variant="split"
+          inset
+        ></v-number-input>
+      </v-col>
+
+      <v-col cols="12" sm="6">
+        <h5>Hide-input</h5>
+
+        <v-number-input
+          hide-input
+          inset
+        ></v-number-input>
+      </v-col>
+    </v-row>
+  </v-container>
+</template>
diff --git a/packages/docs/src/examples/v-number-input/prop-min-max.vue b/packages/docs/src/examples/v-number-input/prop-min-max.vue
new file mode 100644
index 000000000000..3b9d367b404c
--- /dev/null
+++ b/packages/docs/src/examples/v-number-input/prop-min-max.vue
@@ -0,0 +1,15 @@
+<template>
+  <v-container>
+    <v-row>
+      <v-col>
+        <h5>min:10/max:20</h5>
+
+        <v-number-input
+          :max="20"
+          :min="10"
+          :model-value="15"
+        ></v-number-input>
+      </v-col>
+    </v-row>
+  </v-container>
+</template>
diff --git a/packages/docs/src/examples/v-number-input/prop-reverse.vue b/packages/docs/src/examples/v-number-input/prop-reverse.vue
new file mode 100644
index 000000000000..8319e2ec5258
--- /dev/null
+++ b/packages/docs/src/examples/v-number-input/prop-reverse.vue
@@ -0,0 +1,31 @@
+<template>
+  <v-container>
+    <v-row>
+      <v-col cols="12" md="4" sm="4">
+        <h5>Default</h5>
+
+        <v-number-input
+          control-variant="default"
+          reverse
+        ></v-number-input>
+      </v-col>
+
+      <v-col cols="12" md="4" sm="4">
+        <h5>Stacked</h5>
+
+        <v-number-input
+          control-variant="stacked"
+          reverse
+        ></v-number-input>
+      </v-col>
+
+      <v-col cols="12" md="4" sm="4">
+        <h5>Split</h5>
+
+        <v-number-input
+          control-variant="split"
+        ></v-number-input>
+      </v-col>
+    </v-row>
+  </v-container>
+</template>
diff --git a/packages/docs/src/examples/v-number-input/prop-step.vue b/packages/docs/src/examples/v-number-input/prop-step.vue
new file mode 100644
index 000000000000..0c0ef3d16b72
--- /dev/null
+++ b/packages/docs/src/examples/v-number-input/prop-step.vue
@@ -0,0 +1,16 @@
+<template>
+  <v-container>
+    <v-row>
+      <v-col>
+        <h5>step 2; min:10; max:20</h5>
+
+        <v-number-input
+          :max="20"
+          :min="10"
+          :model-value="15"
+          :step="2"
+        ></v-number-input>
+      </v-col>
+    </v-row>
+  </v-container>
+</template>
diff --git a/packages/docs/src/examples/v-number-input/usage.vue b/packages/docs/src/examples/v-number-input/usage.vue
new file mode 100644
index 000000000000..1294a9a61889
--- /dev/null
+++ b/packages/docs/src/examples/v-number-input/usage.vue
@@ -0,0 +1,59 @@
+<template>
+  <ExamplesUsageExample
+    v-model="model"
+    :code="code"
+    :name="name"
+    :options="options"
+  >
+    <div class="text-center">
+      <v-number-input v-bind="props"></v-number-input>
+    </div>
+
+    <template v-slot:configuration>
+      <v-select
+        v-model="controlVariant"
+        :items="controlVariantOptions"
+        label="Control Variant"
+      ></v-select>
+      <v-checkbox v-model="reverse" label="Reverse"></v-checkbox>
+      <v-checkbox v-model="inset" label="Inset"></v-checkbox>
+      <v-checkbox v-model="hideInput" label="HideInput"></v-checkbox>
+      <v-text-field v-model="label" label="Label" clearable></v-text-field>
+    </template>
+  </ExamplesUsageExample>
+</template>
+
+<script setup>
+  const name = ref('v-number-input')
+  const model = ref('default')
+  const options = ['outlined', 'filled', 'solo', 'solo-inverted', 'solo-filled']
+  const controlVariantOptions = ['default', 'stacked', 'split']
+  const reverse = ref(false)
+  const controlVariant = ref('default')
+  const disabled = ref(false)
+  const loading = ref(false)
+  const inset = ref(false)
+  const hideInput = ref(false)
+  const label = ref('')
+
+  const props = computed(() => {
+    return {
+      reverse: reverse.value,
+      controlVariant: controlVariant.value,
+      disabled: disabled.value || undefined,
+      label: label.value,
+      loading: loading.value || undefined,
+      hideInput: hideInput.value,
+      inset: inset.value,
+      variant: model.value !== 'default' ? model.value : undefined,
+    }
+  })
+
+  const slots = computed(() => {
+    return ``
+  })
+
+  const code = computed(() => {
+    return `<v-number-input${propsToString(props.value)}>${slots.value}</v-number-input>`
+  })
+</script>
diff --git a/packages/docs/src/pages/en/components/all.md b/packages/docs/src/pages/en/components/all.md
index 8d21f6c2aeb3..9cdfa4ffabec 100644
--- a/packages/docs/src/pages/en/components/all.md
+++ b/packages/docs/src/pages/en/components/all.md
@@ -232,6 +232,12 @@ Form components are used to collect user input in a variety of ways.
 
 </ComponentsListItem>
 
+<ComponentsListItem name="Number input component" src="number-inputs" labs>
+
+  The number input component is used for collecting numerical data from the user
+
+</ComponentsListItem>
+
 <ComponentsListItem name="OTP Input component" src="otp-input" >
 
   The OTP input component is used for MFA authentication via input field
diff --git a/packages/docs/src/pages/en/components/number-inputs.md b/packages/docs/src/pages/en/components/number-inputs.md
new file mode 100644
index 000000000000..74e0ea7437fb
--- /dev/null
+++ b/packages/docs/src/pages/en/components/number-inputs.md
@@ -0,0 +1,101 @@
+---
+emphasized: true
+meta:
+  title: Number inputs
+  description: The Number input component is used for ...
+  keywords: Number, vuetify number input component, vue number component
+related:
+  - /components/inputs/
+  - /components/text-fields/
+  - /components/forms/
+features:
+  label: 'C: VNumberInput'
+  github: /components/VNumberInput/
+  report: true
+---
+
+# Number inputs
+
+The VNumberInput extends the standard HTML number-type input, ensuring style consistency across browsers as a replacement for `<input type="number">`
+
+<page-features />
+
+::: warning
+
+This feature requires [v3.5.10](/getting-started/release-notes/?version=v3.5.10)
+
+:::
+
+## Installation
+
+Labs components require a manual import and installation of the component.
+
+```js { resource="src/plugins/vuetify.js" }
+import { VNumberInput } from 'vuetify/labs/VNumberInput'
+
+export default createVuetify({
+  components: {
+    VNumberInput,
+  },
+})
+```
+
+## Usage
+
+Here we display a list of settings that could be applied within an application.
+
+<ExamplesUsage name="v-number-input" />
+
+<PromotedEntry />
+
+## API
+
+| Component | Description |
+| - | - |
+| [v-number-input](/api/v-number-input/) | Primary Component |
+
+<ApiInline hide-links />
+
+## Guide
+
+The `v-number-input` component is built upon the `v-field` and `v-input` components. It is used as a replacement for `<input type="number">`, accepting numeric values from the user.
+
+### Props
+
+The `v-number-input` component has support for most of `v-field`'s props and is follows the same design patterns as other inputs.
+
+#### Control-variant
+
+The `control-variant` prop offers an easy way to customize steppers button layout. The following values are valid options: **default**, **stacked** and **split**.
+
+<ExamplesExample file="v-number-input/prop-control-variant" />
+
+#### Reverse
+
+The `reverse` prop automatically changes the stepper buttons' position to the opposite side for both the default and stacked control variants.
+
+<ExamplesExample file="v-number-input/prop-reverse" />
+
+#### Hide-input
+
+The `hide-input` prop hides the input field, allowing only the stepper buttons to be visible. These stepper buttons follow a stacked control-variant layout.
+
+<ExamplesExample file="v-number-input/prop-hide-input" />
+
+#### Inset
+
+The `inset` prop adjusts the style of the stepper buttons by reducing the size of the button dividers.
+
+<ExamplesExample file="v-number-input/prop-inset" />
+
+#### Min/Max
+
+The `min` and `max` props specify the minimum and maximum values accepted by v-number-input, behaving identically to the native min and max attributes for `<input type="number">`.
+
+<ExamplesExample file="v-number-input/prop-min-max" />
+
+#### Step
+
+The `step` prop behaves the same as the `step` attribute in the `<input type="number">`, it defines the incremental steps for adjusting the numeric value.
+
+<ExamplesExample file="v-number-input/prop-step" />
diff --git a/packages/docs/src/pages/en/features/display-and-platform.md b/packages/docs/src/pages/en/features/display-and-platform.md
index f155575f58d1..f66e895086a8 100644
--- a/packages/docs/src/pages/en/features/display-and-platform.md
+++ b/packages/docs/src/pages/en/features/display-and-platform.md
@@ -56,7 +56,7 @@ If you are still using the Options API, you can access the display information o
 | - | - |
 | [useDisplay](/api/use-display/) | Composable |
 
-# Breakpoints and Thresholds
+## Breakpoints and Thresholds
 
 Threshold values generate the ranges used for various breakpoints seen throughout vuetify and the `useDisplay` composable. The system uses an "and up" mentality starting from `xs` at 0px. The default threshold values are displayed below.
 
diff --git a/packages/docs/src/pages/en/getting-started/browser-support.md b/packages/docs/src/pages/en/getting-started/browser-support.md
index 416cff323b12..430758fa9642 100644
--- a/packages/docs/src/pages/en/getting-started/browser-support.md
+++ b/packages/docs/src/pages/en/getting-started/browser-support.md
@@ -15,7 +15,7 @@ Vuetify 3 is a next generation framework that takes advantage of the latest web
 
 <PageFeatures />
 
-<PromotedEntry />
+<VoPromotionsCardVuetify />
 
 ## Browsers
 
diff --git a/packages/docs/src/pages/en/getting-started/contributing.md b/packages/docs/src/pages/en/getting-started/contributing.md
index 079efaac4347..e5b542f59f6a 100644
--- a/packages/docs/src/pages/en/getting-started/contributing.md
+++ b/packages/docs/src/pages/en/getting-started/contributing.md
@@ -15,7 +15,7 @@ Vuetify is made possible by an amazing community that submits issues, creates pu
 
 <PageFeatures />
 
-<PromotedEntry />
+<VoPromotionsCardVuetify />
 
 It is our job to enable you to create amazing applications. A lot of the time, you come across something that can be made better. Maybe you find a bug, or you have an idea for additional functionality. That's great! It's as easy as cloning the Vuetify repository to get started working in a development environment.
 
diff --git a/packages/docs/src/pages/en/getting-started/frequently-asked-questions.md b/packages/docs/src/pages/en/getting-started/frequently-asked-questions.md
index fb8dc7a3702e..6e8ea461048c 100644
--- a/packages/docs/src/pages/en/getting-started/frequently-asked-questions.md
+++ b/packages/docs/src/pages/en/getting-started/frequently-asked-questions.md
@@ -15,7 +15,7 @@ Stuck on a particular problem? Check some of these common gotchas before creatin
 
 <PageFeatures />
 
-<PromotedPromoted slug="discord-subscriber-help" />
+<VoPromotionsCardHighlight slug="vuetify-discord-subscriber-help" />
 
 ## Questions
 
diff --git a/packages/docs/src/pages/en/getting-started/installation.md b/packages/docs/src/pages/en/getting-started/installation.md
index 782312315ae1..a0460ebb1d22 100644
--- a/packages/docs/src/pages/en/getting-started/installation.md
+++ b/packages/docs/src/pages/en/getting-started/installation.md
@@ -20,7 +20,7 @@ Get started with Vuetify, the world’s most popular Vue.js framework for buildi
 
 <PageFeatures />
 
-<PromotedEntry />
+<VoPromotionsCardHighlight slug="vuemastery-getting-started" />
 
 ## Installation
 
diff --git a/packages/docs/src/pages/en/getting-started/release-notes.md b/packages/docs/src/pages/en/getting-started/release-notes.md
index ed0e5796e706..1c2c378ea737 100644
--- a/packages/docs/src/pages/en/getting-started/release-notes.md
+++ b/packages/docs/src/pages/en/getting-started/release-notes.md
@@ -16,6 +16,6 @@ The Vuetify team performs releases on a weekly basis.
 
 <PageFeatures />
 
-<DocReleases />
+<VoPromotionsCardVuetify />
 
-<PromotedEntry />
+<DocReleases />
diff --git a/packages/docs/src/pages/en/getting-started/unit-testing.md b/packages/docs/src/pages/en/getting-started/unit-testing.md
index 8b261843f454..56626b030064 100644
--- a/packages/docs/src/pages/en/getting-started/unit-testing.md
+++ b/packages/docs/src/pages/en/getting-started/unit-testing.md
@@ -15,7 +15,7 @@ Add regression protection by adding unit tests to your Vuetify application
 
 <PageFeatures />
 
-<PromotedEntry />
+<VoPromotionsCardVuetify />
 
 ## Usage
 
diff --git a/packages/docs/src/pages/en/getting-started/upgrade-guide.md b/packages/docs/src/pages/en/getting-started/upgrade-guide.md
index f2efef7459e5..d6b94603e30c 100644
--- a/packages/docs/src/pages/en/getting-started/upgrade-guide.md
+++ b/packages/docs/src/pages/en/getting-started/upgrade-guide.md
@@ -21,8 +21,6 @@ This page contains a detailed list of breaking changes and the steps required to
   <span class="text-h6">Many of the changes on this page can be applied automatically using [eslint-plugin-vuetify](https://www.npmjs.com/package/eslint-plugin-vuetify/)</span>
 :::
 
-<PromotedEntry />
-
 ::: info
 
 Before upgrading, make sure to consult the Official [Vue 3 Migration Guide](https://v3-migration.vuejs.org/)
diff --git a/packages/docs/src/pages/en/getting-started/wireframes.md b/packages/docs/src/pages/en/getting-started/wireframes.md
index 5400663dbaa0..09c5fd35c35d 100644
--- a/packages/docs/src/pages/en/getting-started/wireframes.md
+++ b/packages/docs/src/pages/en/getting-started/wireframes.md
@@ -15,7 +15,7 @@ The Vuetify **layout system** makes it easy to rapidly scaffold an application's
 
 <PageFeatures />
 
-<PromotedEntry />
+<VoPromotionsCardVuetify />
 
 ## Examples
 
diff --git a/packages/docs/src/pages/en/index.md b/packages/docs/src/pages/en/index.md
index e3397693484a..50c5d7f92af3 100644
--- a/packages/docs/src/pages/en/index.md
+++ b/packages/docs/src/pages/en/index.md
@@ -24,17 +24,21 @@ The continued development and maintenance of Vuetify is made possible by these g
 
 <HomeSponsors />
 
-<br>
+<v-divider style="max-width: 500px;" class="mx-auto my-16" />
 
-<v-divider style="max-width: 500px;" class="mx-auto" />
+## Templates Built With Vuetify
 
-<br>
+Check out these premium templates built using Vuetify.{style="max-width: 568px" .mx-auto .px-4}
+
+<DocPremiumThemesGallery />
+
+<v-divider style="max-width: 500px;" class="mx-auto my-16" />
 
 ## Made With Vuetify
 
 Check out these beautiful apps, plugins, and themes built using Vuetify.{style="max-width: 568px" .mx-auto .px-4}
 
-<DocMadeWithVuetifyGallery class="pa-3" />
+<DocMadeWithVuetifyGallery class="pa-3 mb-4" />
 
 <DocMadeWithVuetifyLink />
 
diff --git a/packages/docs/src/pages/en/introduction/why-vuetify.md b/packages/docs/src/pages/en/introduction/why-vuetify.md
index 3665bdb157ba..048577a79810 100644
--- a/packages/docs/src/pages/en/introduction/why-vuetify.md
+++ b/packages/docs/src/pages/en/introduction/why-vuetify.md
@@ -16,7 +16,7 @@ Learn more about what Vuetify is, how to create an application from scratch, bro
 
 <PageFeatures />
 
-<PromotedEntry />
+<VoPromotionsCardVuetify />
 
 ## What is Vuetify?
 
@@ -27,6 +27,8 @@ Since its initial release in 2014, [Vue.js](https://vuejs.org/) has grown to be
 
 ## Getting started
 
+<VoPromotionsCardHighlight slug="vuemastery-getting-started" class="mb-4" />
+
 The fastest way to try Vuetify is in the browser at [Vuetify Play](https://play.vuetifyjs.com/). For a complete list of installation options please navigate to the [Installation page](/getting-started/installation/).
 
 ## Why Vuetify? { id="why-vuetify" }
diff --git a/packages/docs/src/pages/en/labs/introduction.md b/packages/docs/src/pages/en/labs/introduction.md
index f375816514b1..408a46235971 100644
--- a/packages/docs/src/pages/en/labs/introduction.md
+++ b/packages/docs/src/pages/en/labs/introduction.md
@@ -79,6 +79,7 @@ The following is a list of available and up-and-coming components for use with L
 | [v-calendar](/components/calendars/) | A calendar component | [v3.4.9](/getting-started/release-notes/?version=v3.4.9) |
 | [v-empty-state](/components/empty-states/) | A component for displaying empty states | [v3.5.7](/getting-started/release-notes/?version=v3.5.7) |
 | [v-fab](/components/floating-action-buttons/) | A layout aware [v-btn](/components/buttons/) | [v3.5.7](/getting-started/release-notes/?version=v3.5.7) |
+| [v-number-input](/components/number-input/) | A component for numerical data | [v3.5.10](/getting-started/release-notes/?version=v3.5.10) |
 | [v-speed-dial](/components/speed-dials/) | A component for display actions | [v3.5.8](/getting-started/release-notes/?version=v3.5.8) |
 | [v-sparkline](/components/sparklines/) | A basic data display component | [v3.5.5](/getting-started/release-notes/?version=v3.5.5) |
 | [v-treeview](/components/treeview/) | A treeview component | [v3.5.9](/getting-started/release-notes/?version=v3.5.9) |
diff --git a/packages/docs/src/plugins/global-components.ts b/packages/docs/src/plugins/global-components.ts
index 1f1a9853c033..0f40caa98f45 100644
--- a/packages/docs/src/plugins/global-components.ts
+++ b/packages/docs/src/plugins/global-components.ts
@@ -22,6 +22,7 @@ import DocVueJobs from '@/components/doc/VueJobs.vue'
 import DocMadeWithVueAttribution from '@/components/doc/MadeWithVueAttribution.vue'
 import DocMadeWithVuetifyGallery from '@/components/doc/MadeWithVuetifyGallery.vue'
 import DocMadeWithVuetifyLink from '@/components/doc/MadeWithVuetifyLink.vue'
+import DocPremiumThemesGallery from '@/components/doc/PremiumThemesGallery.vue'
 import DocReleases from '@/components/doc/Releases.vue'
 import DocThemeVendor from '@/components/doc/ThemeVendor.vue'
 import ExamplesExample from '@/components/examples/Example.vue'
@@ -73,6 +74,7 @@ export function installGlobalComponents (app: App) {
     .component('DocMadeWithVueAttribution', DocMadeWithVueAttribution)
     .component('DocMadeWithVuetifyGallery', DocMadeWithVuetifyGallery)
     .component('DocMadeWithVuetifyLink', DocMadeWithVuetifyLink)
+    .component('DocPremiumThemesGallery', DocPremiumThemesGallery)
     .component('DocReleases', DocReleases)
     .component('DocThemeVendor', DocThemeVendor)
     .component('ExamplesExample', ExamplesExample)
diff --git a/packages/docs/src/service-worker.js b/packages/docs/src/service-worker.js
index 87ccd5dcbe9f..4f2c7f5761ed 100644
--- a/packages/docs/src/service-worker.js
+++ b/packages/docs/src/service-worker.js
@@ -53,6 +53,8 @@ self.addEventListener('activate', event => {
 self.addEventListener('fetch', event => {
   const url = new URL(event.request.url, location.href)
 
+  if (!['http:', 'https:'].includes(url.protocol)) return
+
   if (event.request.method !== 'GET') return
 
   if (
@@ -102,24 +104,31 @@ function getCacheKeyForUrl (url) {
 
 async function networkFirst (request) {
   const cache = await openCache('runtime')
+  const fromNetwork = fetch(request).then(response => ensureCacheableResponse(response)).catch(() => null)
+  const race = Promise.race([
+    fromNetwork,
+    new Promise(resolve => setTimeout(() => resolve('timeout'), 3000)),
+  ])
 
-  let response
   try {
-    response = ensureCacheableResponse(await fetch(request))
+    const response = await race
+    if (response === 'timeout' || !response) {
+      const cached = await caches.match(request)
+      if (cached) return cached
+      throw new Error('Network timeout and no cache available')
+    }
+    const is400 = response?.status >= 400 && response?.status < 500
+    if (response?.status === 200) {
+      cache.put(request, response.clone())
+    } else if (!is400) {
+      await cache.delete(request)
+    }
+    return response
   } catch (e) {
     console.warn('[SW] Failed to fetch', e)
-  }
-  const is400 = response?.status >= 400 && response?.status < 500
-  if (response?.status === 200) {
-    cache.put(request, response.clone())
-  } else if (!is400) {
     const cached = await caches.match(request)
-    if (cached) return cached
-  } else {
-    await cache.delete(request)
+    return cached || Response.error()
   }
-
-  return response
 }
 
 async function getFallbackDocument () {
@@ -199,7 +208,7 @@ function createCacheKey (entry) {
 
   return {
     cacheKey: cacheKeyUrl.href,
-    url: new URL(url, location.href).href,
+    url: cacheKeyUrl.href,
   }
 }
 
diff --git a/packages/docs/vite.config.mts b/packages/docs/vite.config.mts
index d7508d54a0cf..2205f6b7b3fa 100644
--- a/packages/docs/vite.config.mts
+++ b/packages/docs/vite.config.mts
@@ -79,7 +79,15 @@ export default defineConfig(({ command, mode, ssrBuild }) => {
         ],
         imports: [
           {
-            '@vuetify/one': ['createOne', 'useAuthStore', 'useHttpStore', 'useOneStore', 'useUserStore', 'useSettingsStore'],
+            '@vuetify/one': [
+              'createOne',
+              'useAuthStore',
+              'useHttpStore',
+              'useOneStore',
+              'useUserStore',
+              'useSettingsStore',
+              'useProductsStore',
+            ],
             'lodash-es': ['camelCase', 'kebabCase', 'upperFirst'],
             pinia: ['defineStore', 'storeToRefs'],
             vue: [
diff --git a/packages/vuetify/package.json b/packages/vuetify/package.json
index 2ef697b69013..f5048d952a38 100755
--- a/packages/vuetify/package.json
+++ b/packages/vuetify/package.json
@@ -1,7 +1,7 @@
 {
   "name": "vuetify",
   "description": "Vue Material Component Framework",
-  "version": "3.5.9",
+  "version": "3.5.11",
   "author": {
     "name": "John Leider",
     "email": "john@vuetifyjs.com"
@@ -173,10 +173,10 @@
   },
   "peerDependencies": {
     "typescript": ">=4.7",
-    "vite-plugin-vuetify": ">=1.0.0-alpha.12",
+    "vite-plugin-vuetify": ">=1.0.0",
     "vue": "^3.3.0",
     "vue-i18n": "^9.0.0",
-    "webpack-plugin-vuetify": ">=2.0.0-alpha.11"
+    "webpack-plugin-vuetify": ">=2.0.0"
   },
   "peerDependenciesMeta": {
     "typescript": {
diff --git a/packages/vuetify/src/components/VBreadcrumbs/VBreadcrumbs.tsx b/packages/vuetify/src/components/VBreadcrumbs/VBreadcrumbs.tsx
index 5ed814505e75..c9af34e5c013 100644
--- a/packages/vuetify/src/components/VBreadcrumbs/VBreadcrumbs.tsx
+++ b/packages/vuetify/src/components/VBreadcrumbs/VBreadcrumbs.tsx
@@ -25,10 +25,12 @@ import type { PropType } from 'vue'
 import type { LinkProps } from '@/composables/router'
 import type { GenericProps } from '@/util'
 
-export type BreadcrumbItem = string | (Partial<LinkProps> & {
+export type InternalBreadcrumbItem = Partial<LinkProps> & {
   title: string
   disabled?: boolean
-})
+}
+
+export type BreadcrumbItem = string | InternalBreadcrumbItem
 
 export const makeVBreadcrumbsProps = propsFactory({
   activeClass: String,
@@ -58,9 +60,9 @@ export const VBreadcrumbs = genericComponent<new <T extends BreadcrumbItem>(
   },
   slots: {
     prepend: never
-    title: { item: T, index: number }
+    title: { item: InternalBreadcrumbItem, index: number }
     divider: { item: T, index: number }
-    item: { item: T, index: number }
+    item: { item: InternalBreadcrumbItem, index: number }
     default: never
   }
 ) => GenericProps<typeof props, typeof slots>>()({
diff --git a/packages/vuetify/src/components/VDatePicker/VDatePickerMonth.tsx b/packages/vuetify/src/components/VDatePicker/VDatePickerMonth.tsx
index 03c31f44a2ca..d29d8893202e 100644
--- a/packages/vuetify/src/components/VDatePicker/VDatePickerMonth.tsx
+++ b/packages/vuetify/src/components/VDatePicker/VDatePickerMonth.tsx
@@ -55,6 +55,13 @@ export const VDatePickerMonth = genericComponent<VDatePickerMonthSlots>()({
     const rangeStart = shallowRef()
     const rangeStop = shallowRef()
 
+    if (props.multiple === 'range' && model.value.length > 0) {
+      rangeStart.value = model.value[0]
+      if (model.value.length > 1) {
+        rangeStop.value = model.value[model.value.length - 1]
+      }
+    }
+
     const atMax = computed(() => {
       const max = ['number', 'string'].includes(typeof props.multiple) ? Number(props.multiple) : Infinity
 
@@ -68,15 +75,15 @@ export const VDatePickerMonth = genericComponent<VDatePickerMonthSlots>()({
         rangeStart.value = _value
         model.value = [rangeStart.value]
       } else if (!rangeStop.value) {
-        if (adapter.isSameDay(value, rangeStart.value)) {
+        if (adapter.isSameDay(_value, rangeStart.value)) {
           rangeStart.value = undefined
           model.value = []
           return
-        } else if (adapter.isBefore(value, rangeStart.value)) {
-          rangeStop.value = rangeStart.value
+        } else if (adapter.isBefore(_value, rangeStart.value)) {
+          rangeStop.value = adapter.endOfDay(rangeStart.value)
           rangeStart.value = _value
         } else {
-          rangeStop.value = _value
+          rangeStop.value = adapter.endOfDay(_value)
         }
 
         const diff = adapter.getDiff(rangeStop.value, rangeStart.value, 'days')
diff --git a/packages/vuetify/src/components/VDatePicker/__tests__/VDatePicker.spec.cy.tsx b/packages/vuetify/src/components/VDatePicker/__tests__/VDatePicker.spec.cy.tsx
index 7b68ddc38469..9d328f6133dc 100644
--- a/packages/vuetify/src/components/VDatePicker/__tests__/VDatePicker.spec.cy.tsx
+++ b/packages/vuetify/src/components/VDatePicker/__tests__/VDatePicker.spec.cy.tsx
@@ -21,4 +21,23 @@ describe('VDatePicker', () => {
         expect(model.value).to.have.length(11)
       })
   })
+
+  it('selects a range of dates across month boundary', () => {
+    const model = ref<unknown[]>([])
+    cy.mount(() => (
+      <Application>
+        <VDatePicker v-model={ model.value } multiple="range" />
+      </Application>
+    ))
+
+    cy.get('.v-date-picker-controls__month-btn').click()
+    cy.get('.v-date-picker-months__content').contains('Jan').click()
+    cy.get('.v-date-picker-month__day').contains(7).click()
+    cy.get('.v-date-picker-controls__month-btn').click()
+    cy.get('.v-date-picker-months__content').contains('Feb').click()
+    cy.get('.v-date-picker-month__day').contains(7).click()
+      .then(() => {
+        expect(model.value).to.have.length(32)
+      })
+  })
 })
diff --git a/packages/vuetify/src/components/VField/VField.sass b/packages/vuetify/src/components/VField/VField.sass
index b5800fe10c8f..668f57085507 100644
--- a/packages/vuetify/src/components/VField/VField.sass
+++ b/packages/vuetify/src/components/VField/VField.sass
@@ -453,6 +453,8 @@
 
   .v-field--variant-outlined &
     top: calc(100% - 3px)
+    width: calc(100% - #{$field-border-width} * 2)
+    left: $field-border-width
 
 /* endregion */
 /* region OVERLAY */
diff --git a/packages/vuetify/src/components/VField/VField.tsx b/packages/vuetify/src/components/VField/VField.tsx
index 9a64ada45229..265aff40c071 100644
--- a/packages/vuetify/src/components/VField/VField.tsx
+++ b/packages/vuetify/src/components/VField/VField.tsx
@@ -212,7 +212,7 @@ export const VField = genericComponent<new <T>(
 
     useRender(() => {
       const isOutlined = props.variant === 'outlined'
-      const hasPrepend = (slots['prepend-inner'] || props.prependInnerIcon)
+      const hasPrepend = !!(slots['prepend-inner'] || props.prependInnerIcon)
       const hasClear = !!(props.clearable || slots.clear)
       const hasAppend = !!(slots['append-inner'] || props.appendInnerIcon || hasClear)
       const label = () => (
diff --git a/packages/vuetify/src/components/VIcon/VIcon.sass b/packages/vuetify/src/components/VIcon/VIcon.sass
index 2da9b7376201..1585cf46fcf4 100644
--- a/packages/vuetify/src/components/VIcon/VIcon.sass
+++ b/packages/vuetify/src/components/VIcon/VIcon.sass
@@ -22,6 +22,10 @@
   &--clickable
     cursor: pointer
 
+  &--disabled
+    pointer-events: none
+    opacity: $icon-disabled-opacity
+
   @each $name in settings.$sizes
     &--size-#{$name}
       font-size: calc(var(--v-icon-size-multiplier) * #{map.get($icon-sizes, $name)})
diff --git a/packages/vuetify/src/components/VIcon/VIcon.tsx b/packages/vuetify/src/components/VIcon/VIcon.tsx
index bd9a372eff39..4167c703d2a4 100644
--- a/packages/vuetify/src/components/VIcon/VIcon.tsx
+++ b/packages/vuetify/src/components/VIcon/VIcon.tsx
@@ -15,6 +15,7 @@ import { convertToUnit, flattenFragments, genericComponent, propsFactory, useRen
 
 export const makeVIconProps = propsFactory({
   color: String,
+  disabled: Boolean,
   start: Boolean,
   end: Boolean,
   icon: IconValue,
@@ -45,6 +46,7 @@ export const VIcon = genericComponent()({
           node.type === Text && node.children && typeof node.children === 'string'
         )[0]?.children as string
       }
+      const hasClick = !!(attrs.onClick || attrs.onClickOnce)
 
       return (
         <iconData.value.component
@@ -57,7 +59,8 @@ export const VIcon = genericComponent()({
             sizeClasses.value,
             textColorClasses.value,
             {
-              'v-icon--clickable': !!attrs.onClick,
+              'v-icon--clickable': hasClick,
+              'v-icon--disabled': props.disabled,
               'v-icon--start': props.start,
               'v-icon--end': props.end,
             },
@@ -72,8 +75,9 @@ export const VIcon = genericComponent()({
             textColorStyles.value,
             props.style,
           ]}
-          role={ attrs.onClick ? 'button' : undefined }
-          aria-hidden={ !attrs.onClick }
+          role={ hasClick ? 'button' : undefined }
+          aria-hidden={ !hasClick }
+          tabindex={ hasClick ? props.disabled ? -1 : 0 : undefined }
         >
           { slotValue }
         </iconData.value.component>
diff --git a/packages/vuetify/src/components/VIcon/_variables.scss b/packages/vuetify/src/components/VIcon/_variables.scss
index b376aa18e543..8d21b4f58437 100644
--- a/packages/vuetify/src/components/VIcon/_variables.scss
+++ b/packages/vuetify/src/components/VIcon/_variables.scss
@@ -3,6 +3,7 @@
 @use '../../styles/tools';
 
 // VIcon
+$icon-disabled-opacity: 0.38 !default;
 $icon-left-margin-left: map.get(settings.$grid-gutters, 'md') !default;
 $icon-letter-spacing: normal !default;
 $icon-line-height: 1 !default;
diff --git a/packages/vuetify/src/components/VList/VListItem.tsx b/packages/vuetify/src/components/VList/VListItem.tsx
index 54cf2ab1fc53..a273e4fa5682 100644
--- a/packages/vuetify/src/components/VList/VListItem.tsx
+++ b/packages/vuetify/src/components/VList/VListItem.tsx
@@ -178,9 +178,9 @@ export const VListItem = genericComponent<VListItemSlots>()({
 
       link.navigate?.(e)
 
-      if (root.activatable) {
+      if (root.activatable.value) {
         activate(!isActivated.value, e)
-      } else if (root.selectable) {
+      } else if (root.selectable.value) {
         select(!isSelected.value, e)
       } else if (props.value != null) {
         select(!isSelected.value, e)
diff --git a/packages/vuetify/src/components/VMenu/VMenu.tsx b/packages/vuetify/src/components/VMenu/VMenu.tsx
index 08bebfa5458f..74f643e20157 100644
--- a/packages/vuetify/src/components/VMenu/VMenu.tsx
+++ b/packages/vuetify/src/components/VMenu/VMenu.tsx
@@ -135,6 +135,9 @@ export const VMenu = genericComponent<OverlaySlots>()({
           isActive.value = false
           overlay.value?.activatorEl?.focus()
         }
+      } else if (['Enter', ' '].includes(e.key) && props.closeOnContentClick) {
+        isActive.value = false
+        parent?.closeParents()
       }
     }
 
diff --git a/packages/vuetify/src/components/VNavigationDrawer/VNavigationDrawer.sass b/packages/vuetify/src/components/VNavigationDrawer/VNavigationDrawer.sass
index 839adea358ee..7a9bacbcf5e0 100644
--- a/packages/vuetify/src/components/VNavigationDrawer/VNavigationDrawer.sass
+++ b/packages/vuetify/src/components/VNavigationDrawer/VNavigationDrawer.sass
@@ -70,7 +70,8 @@
   width: 100%
   z-index: -1
 
-  img
+  // TODO: remove in v4
+  img:not(.v-img__img)
     height: $navigation-drawer-img-height
     object-fit: $navigation-drawer-img-object-fit
     width: $navigation-drawer-img-width
diff --git a/packages/vuetify/src/components/VNavigationDrawer/VNavigationDrawer.tsx b/packages/vuetify/src/components/VNavigationDrawer/VNavigationDrawer.tsx
index 9cbde45a8b0b..346e7a4668c8 100644
--- a/packages/vuetify/src/components/VNavigationDrawer/VNavigationDrawer.tsx
+++ b/packages/vuetify/src/components/VNavigationDrawer/VNavigationDrawer.tsx
@@ -1,6 +1,10 @@
 // Styles
 import './VNavigationDrawer.sass'
 
+// Components
+import { VDefaultsProvider } from '@/components/VDefaultsProvider'
+import { VImg } from '@/components/VImg'
+
 // Composables
 import { useSticky } from './sticky'
 import { useTouch } from './touch'
@@ -249,10 +253,29 @@ export const VNavigationDrawer = genericComponent<VNavigationDrawerSlots>()({
           >
             { hasImage && (
               <div key="image" class="v-navigation-drawer__img">
-                { slots.image
-                  ? slots.image?.({ image: props.image })
-                  : (<img src={ props.image } alt="" />)
-                }
+                { !slots.image ? (
+                  <VImg
+                    key="image-img"
+                    alt=""
+                    cover
+                    height="inherit"
+                    src={ props.image }
+                  />
+                ) : (
+                  <VDefaultsProvider
+                    key="image-defaults"
+                    disabled={ !props.image }
+                    defaults={{
+                      VImg: {
+                        alt: '',
+                        cover: true,
+                        height: 'inherit',
+                        src: props.image,
+                      },
+                    }}
+                    v-slots:default={ slots.image }
+                  />
+                )}
               </div>
             )}
 
diff --git a/packages/vuetify/src/components/VOtpInput/VOtpInput.tsx b/packages/vuetify/src/components/VOtpInput/VOtpInput.tsx
index 27ab3bec289d..181e41c1392a 100644
--- a/packages/vuetify/src/components/VOtpInput/VOtpInput.tsx
+++ b/packages/vuetify/src/components/VOtpInput/VOtpInput.tsx
@@ -100,10 +100,11 @@ export const VOtpInput = genericComponent<VOtpInputSlots>()({
     function onInput () {
       // The maxlength attribute doesn't work for the number type input, so the text type is used.
       // The following logic simulates the behavior of a number input.
-      if (props.type === 'number' && /[^0-9]/g.test(current.value.value)) {
+      if (isValidNumber(current.value.value)) {
         current.value.value = ''
         return
       }
+
       const array = model.value.slice()
       const value = current.value.value
 
@@ -165,7 +166,11 @@ export const VOtpInput = genericComponent<VOtpInputSlots>()({
       e.preventDefault()
       e.stopPropagation()
 
-      model.value = (e?.clipboardData?.getData('Text') ?? '').split('')
+      const clipboardText = e?.clipboardData?.getData('Text') ?? ''
+
+      if (isValidNumber(clipboardText)) return
+
+      model.value = clipboardText.split('')
 
       inputRef.value?.[index].blur()
     }
@@ -186,6 +191,10 @@ export const VOtpInput = genericComponent<VOtpInputSlots>()({
       focusIndex.value = -1
     }
 
+    function isValidNumber (value: string) {
+      return props.type === 'number' && /[^0-9]/g.test(value)
+    }
+
     provideDefaults({
       VField: {
         color: computed(() => props.color),
diff --git a/packages/vuetify/src/components/VOverlay/VOverlay.tsx b/packages/vuetify/src/components/VOverlay/VOverlay.tsx
index 5acfa5dbf9f6..dd257f4aadbe 100644
--- a/packages/vuetify/src/components/VOverlay/VOverlay.tsx
+++ b/packages/vuetify/src/components/VOverlay/VOverlay.tsx
@@ -162,6 +162,7 @@ export const VOverlay = genericComponent<OverlaySlots>()({
     })
 
     const root = ref<HTMLElement>()
+    const scrimEl = ref<HTMLElement>()
     const contentEl = ref<HTMLElement>()
     const { contentStyles, updateLocation } = useLocationStrategies(props, {
       isRtl,
@@ -184,8 +185,11 @@ export const VOverlay = genericComponent<OverlaySlots>()({
       else animateClick()
     }
 
-    function closeConditional () {
-      return isActive.value && globalTop.value
+    function closeConditional (e: Event) {
+      return isActive.value && globalTop.value && (
+        // If using scrim, only close if clicking on it rather than anything opened on top
+        !props.scrim || e.target === scrimEl.value
+      )
     }
 
     IN_BROWSER && watch(isActive, val => {
@@ -297,6 +301,7 @@ export const VOverlay = genericComponent<OverlaySlots>()({
               <Scrim
                 color={ scrimColor }
                 modelValue={ isActive.value && !!props.scrim }
+                ref={ scrimEl }
                 { ...scrimEvents.value }
               />
               <MaybeTransition
@@ -332,6 +337,7 @@ export const VOverlay = genericComponent<OverlaySlots>()({
 
     return {
       activatorEl,
+      scrimEl,
       target,
       animateClick,
       contentEl,
diff --git a/packages/vuetify/src/components/VProgressLinear/VProgressLinear.sass b/packages/vuetify/src/components/VProgressLinear/VProgressLinear.sass
index b9e2cfc7b330..50d30b774c62 100644
--- a/packages/vuetify/src/components/VProgressLinear/VProgressLinear.sass
+++ b/packages/vuetify/src/components/VProgressLinear/VProgressLinear.sass
@@ -57,7 +57,6 @@
     right: auto
     top: 0
     width: auto
-    will-change: left, right
 
   .long
     animation-name: indeterminate-ltr
diff --git a/packages/vuetify/src/composables/date/adapters/vuetify.ts b/packages/vuetify/src/composables/date/adapters/vuetify.ts
index 8dd97f14a99e..adbc3a0e664d 100644
--- a/packages/vuetify/src/composables/date/adapters/vuetify.ts
+++ b/packages/vuetify/src/composables/date/adapters/vuetify.ts
@@ -479,7 +479,7 @@ function setYear (date: Date, year: number) {
 }
 
 function startOfDay (date: Date) {
-  return new Date(date.getFullYear(), date.getMonth(), date.getDate())
+  return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0, 0)
 }
 
 function endOfDay (date: Date) {
diff --git a/packages/vuetify/src/composables/form.ts b/packages/vuetify/src/composables/form.ts
index e90bd0e2d7b2..911a04f2380e 100644
--- a/packages/vuetify/src/composables/form.ts
+++ b/packages/vuetify/src/composables/form.ts
@@ -14,8 +14,8 @@ export interface FormProvide {
   register: (item: {
     id: number | string
     validate: () => Promise<string[]>
-    reset: () => void
-    resetValidation: () => void
+    reset: () => Promise<void>
+    resetValidation: () => Promise<void>
   }) => void
   unregister: (id: number | string) => void
   update: (id: number | string, isValid: boolean | null, errorMessages: string[]) => void
@@ -30,8 +30,8 @@ export interface FormProvide {
 export interface FormField {
   id: number | string
   validate: () => Promise<string[]>
-  reset: () => void
-  resetValidation: () => void
+  reset: () => Promise<void>
+  resetValidation: () => Promise<void>
   isValid: boolean | null
   errorMessages: string[]
 }
diff --git a/packages/vuetify/src/composables/theme.ts b/packages/vuetify/src/composables/theme.ts
index f9aeca9bd250..a261035cd333 100644
--- a/packages/vuetify/src/composables/theme.ts
+++ b/packages/vuetify/src/composables/theme.ts
@@ -255,7 +255,7 @@ export function createTheme (options?: ThemeOptions): ThemeInstance & { install:
   const styles = computed(() => {
     const lines: string[] = []
 
-    if (current.value.dark) {
+    if (current.value?.dark) {
       createCssClass(lines, ':root', ['color-scheme: dark'])
     }
 
diff --git a/packages/vuetify/src/composables/transition.ts b/packages/vuetify/src/composables/transition.ts
index 98458bb84e06..79c088f00763 100644
--- a/packages/vuetify/src/composables/transition.ts
+++ b/packages/vuetify/src/composables/transition.ts
@@ -35,7 +35,7 @@ export const MaybeTransition: FunctionalComponent<MaybeTransitionProps> = (props
         : customProps as any,
       typeof transition === 'string'
         ? {}
-        : { disabled, group },
+        : Object.fromEntries(Object.entries({ disabled, group }).filter(([_, v]) => v !== undefined)),
       rest as any,
     ),
     slots
diff --git a/packages/vuetify/src/composables/validation.ts b/packages/vuetify/src/composables/validation.ts
index 347eeec9f089..2b250cb02d55 100644
--- a/packages/vuetify/src/composables/validation.ts
+++ b/packages/vuetify/src/composables/validation.ts
@@ -166,15 +166,16 @@ export function useValidation (
     form?.update(uid.value, isValid.value, errorMessages.value)
   })
 
-  function reset () {
+  async function reset () {
     model.value = null
-    nextTick(resetValidation)
+    await nextTick()
+    await resetValidation()
   }
 
-  function resetValidation () {
+  async function resetValidation () {
     isPristine.value = true
     if (!validateOn.value.lazy) {
-      validate(true)
+      await validate(true)
     } else {
       internalErrorMessages.value = []
     }
diff --git a/packages/vuetify/src/labs/VNumberInput/VNumberInput.sass b/packages/vuetify/src/labs/VNumberInput/VNumberInput.sass
new file mode 100644
index 000000000000..43b276350598
--- /dev/null
+++ b/packages/vuetify/src/labs/VNumberInput/VNumberInput.sass
@@ -0,0 +1,47 @@
+@use 'sass:selector'
+@use './variables' as *
+
+.v-number-input
+  $root: &
+  $control-root: #{selector.append($root, '__control')}
+
+  input[type="number"]
+    -moz-appearance: textfield
+
+    &::-webkit-outer-spin-button,
+    &::-webkit-inner-spin-button
+      -webkit-appearance: none
+
+  .v-field
+    padding-inline-end: 0
+    padding-inline-start: 0
+
+  &--inset
+    .v-divider
+      height: $number-input-inset-divider-size
+      width: $number-input-inset-divider-size
+      align-self: center
+
+  &--split
+    .v-field__input
+      text-align: center
+
+  &--stacked 
+    #{$control-root}
+      flex-direction: column-reverse
+      .v-btn
+        flex: 1
+
+  &--hide-input
+    .v-field
+      flex: none
+      &__input
+        width: 0
+        padding-inline: 0
+
+  &__control
+    display: flex
+    height: 100%
+
+    .v-btn
+      background-color: transparent
diff --git a/packages/vuetify/src/labs/VNumberInput/VNumberInput.tsx b/packages/vuetify/src/labs/VNumberInput/VNumberInput.tsx
new file mode 100644
index 000000000000..917827ff9771
--- /dev/null
+++ b/packages/vuetify/src/labs/VNumberInput/VNumberInput.tsx
@@ -0,0 +1,289 @@
+// Styles
+import './VNumberInput.sass'
+
+// Components
+import { VBtn } from '../../components/VBtn'
+import { VDefaultsProvider } from '../../components/VDefaultsProvider'
+import { VDivider } from '../../components/VDivider'
+import { filterFieldProps, makeVFieldProps, VField } from '@/components/VField/VField'
+import { makeVInputProps, VInput } from '@/components/VInput/VInput'
+
+// Composables
+import { makeFocusProps, useFocus } from '@/composables/focus'
+import { useProxiedModel } from '@/composables/proxiedModel'
+
+// Utilities
+import { computed, ref } from 'vue'
+import { filterInputAttrs, genericComponent, only, propsFactory, useRender } from '@/util'
+
+// Types
+import type { PropType } from 'vue'
+import type { VFieldSlots } from '@/components/VField/VField'
+import type { VInputSlots } from '@/components/VInput/VInput'
+
+type ControlSlot = {
+  click: () => void
+}
+
+type VNumberInputSlots = Omit<VInputSlots & VFieldSlots, 'default'> & {
+  increment: ControlSlot
+  decrement: ControlSlot
+}
+
+type ControlVariant = 'default' | 'stacked' | 'split'
+
+const makeVNumberInputProps = propsFactory({
+  controlVariant: {
+    type: String as PropType<ControlVariant>,
+    default: 'default',
+  },
+  inset: Boolean,
+  hideInput: Boolean,
+  min: Number,
+  max: Number,
+  step: Number,
+
+  ...only(makeVInputProps(), [
+    'density',
+    'disabled',
+    'focused',
+    'hideDetails',
+    'hint',
+    'label',
+    'persistentHint',
+    'readonly',
+  ]),
+  ...only(makeVFieldProps(), [
+    'baseColor',
+    'bgColor',
+    'class',
+    'color',
+    'disabled',
+    'error',
+    'loading',
+    'reverse',
+    'rounded',
+    'style',
+    'theme',
+    'variant',
+  ]),
+  ...makeFocusProps(),
+}, 'VNumberInput')
+
+export const VNumberInput = genericComponent<VNumberInputSlots>()({
+  name: 'VNumberInput',
+
+  inheritAttrs: false,
+
+  props: {
+    ...makeVNumberInputProps(),
+
+    modelValue: {
+      type: [Number, String],
+      default: 0,
+    },
+  },
+
+  emits: {
+    'update:modelValue': (val: number) => true,
+  },
+
+  setup (props, { attrs, emit, slots }) {
+    const model = useProxiedModel(props, 'modelValue')
+    const { isFocused, focus, blur } = useFocus(props)
+    const inputRef = ref<HTMLInputElement>()
+
+    function onFocus () {
+      if (!isFocused.value) focus()
+    }
+
+    const controlVariant = computed(() => {
+      return props.hideInput ? 'stacked' : props.controlVariant
+    })
+
+    function toggleUpDown (increment = true) {
+      if (increment) {
+        inputRef.value?.stepUp()
+      } else {
+        inputRef.value?.stepDown()
+      }
+
+      if (inputRef.value) model.value = parseInt(inputRef.value.value, 10)
+    }
+
+    function onClickUp () {
+      toggleUpDown()
+    }
+
+    function onClickDown () {
+      toggleUpDown(false)
+    }
+
+    const incrementSlotProps = computed(() => ({ click: onClickUp }))
+
+    const decrementSlotProps = computed(() => ({ click: onClickDown }))
+
+    useRender(() => {
+      const fieldProps = filterFieldProps(props)
+      const [rootAttrs, inputAttrs] = filterInputAttrs(attrs)
+      const { modelValue: _, ...inputProps } = VInput.filterProps(props)
+
+      function controlNode () {
+        const defaultHeight = controlVariant.value === 'stacked' ? 'auto' : '100%'
+        return (
+          <div class="v-number-input__control">
+            {
+              !slots.decrement ? (
+                <VBtn
+                  flat
+                  key="decrement-btn"
+                  height={ defaultHeight }
+                  icon="$expand"
+                  rounded="0"
+                  size="small"
+                  onClick={ onClickDown }
+                />
+              ) : (
+                <VDefaultsProvider
+                  key="decrement-defaults"
+                  defaults={{
+                    VBtn: {
+                      flat: true,
+                      rounded: '0',
+                      height: defaultHeight,
+                      size: 'small',
+                      icon: '$expand',
+                    },
+                  }}
+                >
+                  { slots.decrement(decrementSlotProps.value) }
+                </VDefaultsProvider>
+              )
+            }
+
+            <VDivider
+              vertical={ controlVariant.value !== 'stacked' }
+            />
+
+            {
+              !slots.increment ? (
+                <VBtn
+                  flat
+                  key="increment-btn"
+                  height={ defaultHeight }
+                  icon="$collapse"
+                  onClick={ onClickUp }
+                  rounded="0"
+                  size="small"
+                />
+              ) : (
+                <VDefaultsProvider
+                  key="increment-defaults"
+                  defaults={{
+                    VBtn: {
+                      flat: true,
+                      height: defaultHeight,
+                      rounded: '0',
+                      size: 'small',
+                      icon: '$collapse',
+                    },
+                  }}
+                >
+                  { slots.increment(incrementSlotProps.value) }
+                </VDefaultsProvider>
+              )
+            }
+          </div>
+        )
+      }
+
+      function dividerNode () {
+        return !props.hideInput && !props.inset ? <VDivider vertical /> : undefined
+      }
+
+      return (
+        <VInput
+          class={[
+            'v-number-input',
+            {
+              'v-number-input--default': controlVariant.value === 'default',
+              'v-number-input--hide-input': props.hideInput,
+              'v-number-input--inset': props.inset,
+              'v-number-input--reverse': props.reverse,
+              'v-number-input--split': controlVariant.value === 'split',
+              'v-number-input--stacked': controlVariant.value === 'stacked',
+            },
+            props.class,
+          ]}
+          { ...rootAttrs }
+          { ...inputProps }
+          focused={ isFocused.value }
+          style={ props.style }
+        >
+          {{
+            ...slots,
+            default: () => (
+              <VField
+                { ...fieldProps }
+                active
+                focused={ isFocused.value }
+              >
+                {{
+                  ...slots,
+                  default: ({
+                    props: { class: fieldClass, ...slotProps },
+                  }) => (
+                    <input
+                      ref={ inputRef }
+                      type="number"
+                      value={ model.value }
+                      class={ fieldClass }
+                      max={ props.max }
+                      min={ props.min }
+                      step={ props.step }
+                      onFocus={ onFocus }
+                      onBlur={ blur }
+                      { ...inputAttrs }
+                    />
+                  ),
+                  'append-inner': controlVariant.value === 'split' ? () => (
+                    <div class="v-number-input__control">
+                      <VDivider vertical />
+
+                      <VBtn
+                        flat
+                        height="100%"
+                        icon="$plus"
+                        tile
+                        onClick={ onClickUp }
+                      />
+                    </div>
+                  ) : (!props.reverse
+                    ? () => <>{ dividerNode() }{ controlNode() }</>
+                    : undefined),
+                  'prepend-inner': controlVariant.value === 'split' ? () => (
+                    <div class="v-number-input__control">
+                      <VBtn
+                        flat
+                        height="100%"
+                        icon="$minus"
+                        tile
+                        onClick={ onClickDown }
+                      />
+
+                      <VDivider vertical />
+                    </div>
+                  ) : (props.reverse
+                    ? () => <>{ controlNode() }{ dividerNode() }</>
+                    : undefined),
+                }}
+              </VField>
+            ),
+          }}
+        </VInput>
+      )
+    })
+  },
+})
+
+export type VNumberInput = InstanceType<typeof VNumberInput>
diff --git a/packages/vuetify/src/labs/VNumberInput/_variables.scss b/packages/vuetify/src/labs/VNumberInput/_variables.scss
new file mode 100644
index 000000000000..16af2fe55be3
--- /dev/null
+++ b/packages/vuetify/src/labs/VNumberInput/_variables.scss
@@ -0,0 +1 @@
+$number-input-inset-divider-size: 55% !default;
diff --git a/packages/vuetify/src/labs/VNumberInput/index.ts b/packages/vuetify/src/labs/VNumberInput/index.ts
new file mode 100644
index 000000000000..20aa5db57c50
--- /dev/null
+++ b/packages/vuetify/src/labs/VNumberInput/index.ts
@@ -0,0 +1 @@
+export { VNumberInput } from './VNumberInput'
diff --git a/packages/vuetify/src/labs/components.ts b/packages/vuetify/src/labs/components.ts
index 695e5631bf6a..f1a34406da6f 100644
--- a/packages/vuetify/src/labs/components.ts
+++ b/packages/vuetify/src/labs/components.ts
@@ -2,6 +2,7 @@ export * from './VCalendar'
 export * from './VConfirmEdit'
 export * from './VEmptyState'
 export * from './VFab'
+export * from './VNumberInput'
 export * from './VPicker'
 export * from './VSparkline'
 export * from './VSpeedDial'
diff --git a/packages/vuetify/src/locale/no.ts b/packages/vuetify/src/locale/no.ts
index 01d33e5de978..9b759347077c 100644
--- a/packages/vuetify/src/locale/no.ts
+++ b/packages/vuetify/src/locale/no.ts
@@ -1,6 +1,6 @@
 export default {
   badge: 'Skilt',
-  open: 'Open',
+  open: 'Åpne',
   close: 'Lukk',
   confirmEdit: {
     ok: 'OK',
diff --git a/yarn.lock b/yarn.lock
index 94d493a1a93d..ff1736f95427 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3949,10 +3949,10 @@
     find-cache-dir "^3.3.2"
     upath "^2.0.1"
 
-"@vuetify/one@^1.2.4":
-  version "1.2.4"
-  resolved "https://registry.yarnpkg.com/@vuetify/one/-/one-1.2.4.tgz#0cd7756100fe2158fc98bdafef61b91abcbdeb02"
-  integrity sha512-Q9Os2+3RdaVv+oxxF+OdJCk+CH7PWVNHJY83Di7LM/9yr/npnW/YyDpoq1pfyHMzuLkfyl8XuKc13izV1D5fDA==
+"@vuetify/one@^1.5.0":
+  version "1.5.0"
+  resolved "https://registry.yarnpkg.com/@vuetify/one/-/one-1.5.0.tgz#c76df35ca8ec7fb55abedfe9d1523fc58d3d5ad5"
+  integrity sha512-nuMPMnMcR87FkbhC8NW0B0fI0S57LXkR6/Zy3dxPGMOoSZ2L5BFk2BYq2fUJ5xtUnghA9SRUcagT6XXLG1mlwA==
 
 "@vueuse/head@^1.3.1":
   version "1.3.1"