diff --git a/frontend/src/metabase/browse/components/BrowseContainer.styled.tsx b/frontend/src/metabase/browse/components/BrowseContainer.styled.tsx
index e6e7cb96839673d5118ec2e8c67c377161114da2..90a42eca12d4df8036e2b51ba1bae4bef0b136da 100644
--- a/frontend/src/metabase/browse/components/BrowseContainer.styled.tsx
+++ b/frontend/src/metabase/browse/components/BrowseContainer.styled.tsx
@@ -59,6 +59,7 @@ export const CenteredEmptyState = styled(EmptyState)`
   flex-flow: column nowrap;
   align-items: center;
   justify-content: center;
+  width: 100%;
   height: 100%;
 `;
 
diff --git a/frontend/src/metabase/browse/components/BrowseModels.tsx b/frontend/src/metabase/browse/components/BrowseModels.tsx
index 02bb684bf957a5dbceb307bd1f590899846f138f..a74eb318f4f523d71e6b2c32fa559f53c38a4b82 100644
--- a/frontend/src/metabase/browse/components/BrowseModels.tsx
+++ b/frontend/src/metabase/browse/components/BrowseModels.tsx
@@ -4,7 +4,7 @@ import { t } from "ttag";
 import NoResults from "assets/img/no_results.svg";
 import { useListRecentsQuery } from "metabase/api";
 import { useFetchModels } from "metabase/common/hooks/use-fetch-models";
-import LoadingAndErrorWrapper from "metabase/components/LoadingAndErrorWrapper";
+import { DelayedLoadingAndErrorWrapper } from "metabase/components/LoadingAndErrorWrapper/DelayedLoadingAndErrorWrapper";
 import { color } from "metabase/lib/colors";
 import {
   PLUGIN_COLLECTIONS,
@@ -78,6 +78,11 @@ export const BrowseModels = () => {
     return filteredRecentModels.slice(0, cap);
   }, [filteredRecentModels, allModels.length]);
 
+  const isEmpty =
+    !recentModelsResult.isLoading &&
+    !modelsResult.isLoading &&
+    !filteredModels.length;
+
   return (
     <BrowseContainer>
       <BrowseHeader>
@@ -106,18 +111,8 @@ export const BrowseModels = () => {
       </BrowseHeader>
       <BrowseMain>
         <BrowseSection>
-          <LoadingAndErrorWrapper
-            error={modelsResult.error || recentModelsResult.error}
-            loading={modelsResult.isLoading || recentModelsResult.isLoading}
-            style={{ flex: 1 }}
-          >
-            {filteredModels.length ? (
-              <Stack mb="lg" spacing="md">
-                <ModelExplanationBanner />
-                <RecentModels models={recentModels} />
-                <ModelsTable models={filteredModels} />
-              </Stack>
-            ) : (
+          <Stack mb="lg" spacing="md" w="100%">
+            {isEmpty ? (
               <CenteredEmptyState
                 title={<Box mb=".5rem">{t`No models here yet`}</Box>}
                 message={
@@ -129,8 +124,35 @@ export const BrowseModels = () => {
                   </Box>
                 }
               />
+            ) : (
+              <>
+                <ModelExplanationBanner />
+                <DelayedLoadingAndErrorWrapper
+                  error={recentModelsResult.error}
+                  loading={
+                    // If the main models result is still pending, the list of recently viewed
+                    // models isn't ready yet, since the number of recently viewed models is
+                    // capped according to the size of the main models result
+                    recentModelsResult.isLoading || modelsResult.isLoading
+                  }
+                  style={{ flex: 1 }}
+                  delay={0}
+                  loader={<RecentModels skeleton />}
+                >
+                  <RecentModels models={recentModels} />
+                </DelayedLoadingAndErrorWrapper>
+                <DelayedLoadingAndErrorWrapper
+                  error={modelsResult.error}
+                  loading={modelsResult.isLoading}
+                  style={{ flex: 1 }}
+                  delay={0}
+                  loader={<ModelsTable skeleton />}
+                >
+                  <ModelsTable models={filteredModels} />
+                </DelayedLoadingAndErrorWrapper>
+              </>
             )}
-          </LoadingAndErrorWrapper>
+          </Stack>
         </BrowseSection>
       </BrowseMain>
     </BrowseContainer>
diff --git a/frontend/src/metabase/browse/components/BrowseModels.unit.spec.tsx b/frontend/src/metabase/browse/components/BrowseModels.unit.spec.tsx
index 8e1d2a07139fd3fbe28e43909ddba7a47157da6e..956d2f64ae8720085f1bf75436b3c00c5e3d8aab 100644
--- a/frontend/src/metabase/browse/components/BrowseModels.unit.spec.tsx
+++ b/frontend/src/metabase/browse/components/BrowseModels.unit.spec.tsx
@@ -279,7 +279,9 @@ describe("BrowseModels", () => {
 
   it("displays the Our Analytics collection if it has a model", async () => {
     setup(25);
-    const modelsTable = await screen.findByRole("table");
+    const modelsTable = await screen.findByRole("table", {
+      name: /Table of models/,
+    });
     expect(modelsTable).toBeInTheDocument();
     expect(
       await screen.findAllByTestId("path-for-collection: Our analytics"),
@@ -297,7 +299,9 @@ describe("BrowseModels", () => {
 
   it("displays collection breadcrumbs", async () => {
     setup(25);
-    const modelsTable = await screen.findByRole("table");
+    const modelsTable = await screen.findByRole("table", {
+      name: /Table of models/,
+    });
     expect(await within(modelsTable).findByText("Model 1")).toBeInTheDocument();
     expect(
       await within(modelsTable).findAllByTestId(
diff --git a/frontend/src/metabase/browse/components/ModelsTable.styled.tsx b/frontend/src/metabase/browse/components/ModelsTable.styled.tsx
index 0ec163605509397dc185c95647ed8e5843260425..3fa1bb0eb0b3e17c829e7d011ed1d45dafcfb8e6 100644
--- a/frontend/src/metabase/browse/components/ModelsTable.styled.tsx
+++ b/frontend/src/metabase/browse/components/ModelsTable.styled.tsx
@@ -8,11 +8,17 @@ import {
 import type { ResponsiveProps } from "metabase/components/ItemsTable/utils";
 import { breakpoints } from "metabase/ui/theme";
 
-export const ModelTableRow = styled.tr`
-  cursor: pointer;
+export const ModelTableRow = styled.tr<{ skeleton?: boolean }>`
   :outline {
     outline: 2px solid var(--mb-color-brand);
   }
+  ${props =>
+    props.skeleton
+      ? `
+    :hover { background-color: unset ! important; }
+    td { cursor: unset ! important; }
+    `
+      : `cursor: pointer;`}
 `;
 
 export const ModelNameLink = styled(ItemLink)`
diff --git a/frontend/src/metabase/browse/components/ModelsTable.tsx b/frontend/src/metabase/browse/components/ModelsTable.tsx
index 706da78740d60ed2b17729c2b666ac09a151d903..d404e51390510c2ca95c053699b3e935953cf4c2 100644
--- a/frontend/src/metabase/browse/components/ModelsTable.tsx
+++ b/frontend/src/metabase/browse/components/ModelsTable.tsx
@@ -1,12 +1,17 @@
-import { useEffect, useState } from "react";
+import {
+  type PropsWithChildren,
+  useEffect,
+  useState,
+  type CSSProperties,
+} from "react";
 import { push } from "react-router-redux";
 import { t } from "ttag";
 
 import EntityItem from "metabase/components/EntityItem";
 import { SortableColumnHeader } from "metabase/components/ItemsTable/BaseItemsTable";
 import {
-  ItemLink,
   ItemNameCell,
+  MaybeItemLink,
   Table,
   TableColumn,
   TBody,
@@ -18,7 +23,14 @@ import { color } from "metabase/lib/colors";
 import { useDispatch, useSelector } from "metabase/lib/redux";
 import * as Urls from "metabase/lib/urls";
 import { getLocale } from "metabase/setup/selectors";
-import { Flex, Icon, type IconProps } from "metabase/ui";
+import {
+  Flex,
+  Icon,
+  type IconProps,
+  type IconName,
+  Skeleton,
+} from "metabase/ui";
+import { Repeat } from "metabase/ui/components/feedback/Skeleton/Repeat";
 import { SortDirection, type SortingOptions } from "metabase-types/api/sorting";
 
 import { trackModelClick } from "../analytics";
@@ -29,6 +41,7 @@ import {
   CollectionBreadcrumbsWithTooltip,
   SimpleCollectionDisplay,
 } from "./CollectionBreadcrumbsWithTooltip";
+import { CollectionsIcon } from "./CollectionBreadcrumbsWithTooltip.styled";
 import { EllipsifiedWithMarkdownTooltip } from "./EllipsifiedWithMarkdownTooltip";
 import {
   ModelCell,
@@ -38,7 +51,9 @@ import {
 import { getModelDescription, sortModels } from "./utils";
 
 export interface ModelsTableProps {
-  models: ModelResult[];
+  models?: ModelResult[];
+  /** True if this component is just rendering a loading skeleton */
+  skeleton?: boolean;
 }
 
 export const itemsTableContainerName = "ItemsTableContainer";
@@ -60,14 +75,18 @@ const DEFAULT_SORTING_OPTIONS: SortingOptions = {
 
 const LARGE_DATASET_THRESHOLD = 500;
 
-export const ModelsTable = ({ models }: ModelsTableProps) => {
+export const ModelsTable = ({
+  models = [],
+  skeleton = false,
+}: ModelsTableProps) => {
   const locale = useSelector(getLocale);
   const localeCode: string | undefined = locale?.code;
 
   // for large datasets, we need to simplify the display to avoid performance issues
   const isLargeDataset = models.length > LARGE_DATASET_THRESHOLD;
 
-  const [showLoading, setShowLoading] = useState(isLargeDataset);
+  const [showLoadingManyRows, setShowLoadingManyRows] =
+    useState(isLargeDataset);
 
   const [sortingOptions, setSortingOptions] = useState<SortingOptions>(
     DEFAULT_SORTING_OPTIONS,
@@ -79,23 +98,25 @@ export const ModelsTable = ({ models }: ModelsTableProps) => {
   const collectionWidth = 38.5;
   const descriptionWidth = 100 - collectionWidth;
 
-  const handleUpdateSortOptions = (newSortingOptions: SortingOptions) => {
-    if (isLargeDataset) {
-      setShowLoading(true);
-    }
-    setSortingOptions(newSortingOptions);
-  };
+  const handleUpdateSortOptions = skeleton
+    ? undefined
+    : (newSortingOptions: SortingOptions) => {
+        if (isLargeDataset) {
+          setShowLoadingManyRows(true);
+        }
+        setSortingOptions(newSortingOptions);
+      };
 
   useEffect(() => {
     // we need a better virtualized table solution for large datasets
     // for now, we show loading text to make this component feel more responsive
-    if (isLargeDataset && showLoading) {
-      setTimeout(() => setShowLoading(false), 10);
+    if (isLargeDataset && showLoadingManyRows) {
+      setTimeout(() => setShowLoadingManyRows(false), 10);
     }
-  }, [isLargeDataset, showLoading, sortedModels]);
+  }, [isLargeDataset, showLoadingManyRows, sortedModels]);
 
   return (
-    <Table>
+    <Table aria-label={skeleton ? undefined : "Table of models"}>
       <colgroup>
         {/* <col> for Name column */}
         <ModelNameColumn containerName={itemsTableContainerName} />
@@ -149,8 +170,12 @@ export const ModelsTable = ({ models }: ModelsTableProps) => {
         </tr>
       </thead>
       <TBody>
-        {showLoading ? (
+        {showLoadingManyRows ? (
           <TableLoader />
+        ) : skeleton ? (
+          <Repeat times={7}>
+            <TBodyRowSkeleton />
+          </Repeat>
         ) : (
           sortedModels.map((model: ModelResult) => (
             <TBodyRow
@@ -168,9 +193,11 @@ export const ModelsTable = ({ models }: ModelsTableProps) => {
 const TBodyRow = ({
   model,
   simpleDisplay,
+  skeleton,
 }: {
   model: ModelResult;
   simpleDisplay: boolean;
+  skeleton?: boolean;
 }) => {
   const icon = getIcon(model);
   const containerName = `collections-path-for-${model.id}`;
@@ -180,6 +207,9 @@ const TBodyRow = ({
   return (
     <ModelTableRow
       onClick={(e: React.MouseEvent) => {
+        if (skeleton) {
+          return;
+        }
         const url = Urls.model({ id, name });
         if ((e.ctrlKey || e.metaKey) && e.button === 0) {
           window.open(url, "_blank");
@@ -195,6 +225,9 @@ const TBodyRow = ({
         model={model}
         icon={icon}
         onClick={() => {
+          if (skeleton) {
+            return;
+          }
           trackModelClick(model.id);
         }}
       />
@@ -236,21 +269,21 @@ const NameCell = ({
   testIdPrefix = "table",
   onClick,
   icon,
-}: {
-  model: ModelResult;
+  children,
+}: PropsWithChildren<{
+  model?: ModelResult;
   testIdPrefix?: string;
   onClick?: () => void;
   icon: IconProps;
-}) => {
-  const { id, name } = model;
-  const headingId = `model-${id}-heading`;
+}>) => {
+  const headingId = `model-${model?.id || "dummy"}-heading`;
   return (
     <ItemNameCell
       data-testid={`${testIdPrefix}-name`}
       aria-labelledby={headingId}
     >
-      <ItemLink
-        to={Urls.model({ id, name })}
+      <MaybeItemLink
+        to={model ? Urls.model({ id: model.id, name: model.name }) : undefined}
         onClick={onClick}
         style={{
           // To align the icons with "Name" in the <th>
@@ -264,8 +297,14 @@ const NameCell = ({
           color={color("brand")}
           style={{ flexShrink: 0 }}
         />
-        <EntityItem.Name name={model.name} variant="list" id={headingId} />
-      </ItemLink>
+        {children || (
+          <EntityItem.Name
+            name={model?.name || ""}
+            variant="list"
+            id={headingId}
+          />
+        )}
+      </MaybeItemLink>
     </ItemNameCell>
   );
 };
@@ -279,3 +318,35 @@ const TableLoader = () => (
     </td>
   </tr>
 );
+
+const CellTextSkeleton = () => {
+  return <Skeleton natural h="16.8px" />;
+};
+
+const TBodyRowSkeleton = ({ style }: { style?: CSSProperties }) => {
+  const icon = { name: "model" as IconName };
+  return (
+    <ModelTableRow skeleton style={style}>
+      {/* Name */}
+      <NameCell icon={icon}>
+        <CellTextSkeleton />
+      </NameCell>
+
+      {/* Collection */}
+      <ModelCell {...collectionProps}>
+        <Flex>
+          <CollectionsIcon name="folder" />
+          <CellTextSkeleton />
+        </Flex>
+      </ModelCell>
+
+      {/* Description */}
+      <ModelCell {...descriptionProps}>
+        <CellTextSkeleton />
+      </ModelCell>
+
+      {/* Adds a border-radius to the table */}
+      <Columns.RightEdge.Cell />
+    </ModelTableRow>
+  );
+};
diff --git a/frontend/src/metabase/browse/components/RecentModels.tsx b/frontend/src/metabase/browse/components/RecentModels.tsx
index db2d358e958ac9cd597a86be43129e955d54e11d..66b750040c38d112f0bbb2856a4232e1954d98bf 100644
--- a/frontend/src/metabase/browse/components/RecentModels.tsx
+++ b/frontend/src/metabase/browse/components/RecentModels.tsx
@@ -2,35 +2,55 @@ import { t } from "ttag";
 
 import PinnedItemCard from "metabase/collections/components/PinnedItemCard";
 import { Box, Text } from "metabase/ui";
+import { Repeat } from "metabase/ui/components/feedback/Skeleton/Repeat";
 import type { RecentCollectionItem } from "metabase-types/api";
 
 import { trackModelClick } from "../analytics";
 
 import { RecentModelsGrid } from "./RecentModels.styled";
 
-export function RecentModels({ models }: { models: RecentCollectionItem[] }) {
-  if (models.length === 0) {
+export function RecentModels({
+  models = [],
+  skeleton,
+}: {
+  models?: RecentCollectionItem[];
+  skeleton?: boolean;
+}) {
+  if (!skeleton && models.length === 0) {
     return null;
   }
-
   const headingId = "recently-viewed-models-heading";
   return (
-    <Box my="lg" role="grid" aria-labelledby={headingId}>
+    <Box
+      w="auto"
+      my="lg"
+      role="grid"
+      aria-labelledby={skeleton ? undefined : headingId}
+      mah={skeleton ? "11rem" : undefined}
+      style={skeleton ? { overflow: "hidden" } : undefined}
+    >
       <Text
-        id={headingId}
+        id={skeleton ? undefined : headingId}
         fw="bold"
         size={16}
         color="text-dark"
         mb="lg"
+        style={{ visibility: skeleton ? "hidden" : undefined }}
       >{t`Recents`}</Text>
       <RecentModelsGrid>
-        {models.map(model => (
-          <PinnedItemCard
-            key={`model-${model.id}`}
-            item={model}
-            onClick={() => trackModelClick(model.id)}
-          />
-        ))}
+        {skeleton ? (
+          <Repeat times={2}>
+            <PinnedItemCard skeleton iconForSkeleton="model" />
+          </Repeat>
+        ) : (
+          models.map(model => (
+            <PinnedItemCard
+              key={`model-${model.id}`}
+              item={model}
+              onClick={() => trackModelClick(model.id)}
+            />
+          ))
+        )}
       </RecentModelsGrid>
     </Box>
   );
diff --git a/frontend/src/metabase/collections/components/PinnedItemCard/PinnedItemCard.styled.tsx b/frontend/src/metabase/collections/components/PinnedItemCard/PinnedItemCard.styled.tsx
index f54a013c0b7b41b2e769269233f197ea9fe7e141..31c3d2a03841a4e1bbecf0df9c5bb2797315e532 100644
--- a/frontend/src/metabase/collections/components/PinnedItemCard/PinnedItemCard.styled.tsx
+++ b/frontend/src/metabase/collections/components/PinnedItemCard/PinnedItemCard.styled.tsx
@@ -1,15 +1,24 @@
+import { css } from "@emotion/react";
 import styled from "@emotion/styled";
 
+import { RawMaybeLink } from "metabase/components/Badge/Badge.styled";
 import Card from "metabase/components/Card";
-import Link from "metabase/core/components/Link";
 import { MarkdownPreview } from "metabase/core/components/MarkdownPreview";
-import { Icon } from "metabase/ui";
+import { Box, type BoxProps, Icon } from "metabase/ui";
 
 export const ItemCard = styled(Card)``;
 
-export const ItemLink = styled(Link)`
+export const ItemLink = styled(RawMaybeLink)<{ to?: string }>`
   display: block;
   height: min-content;
+  ${props =>
+    props.to
+      ? ""
+      : css`
+          ${Body} {
+            cursor: default;
+          }
+        `}
 `;
 
 export const ItemIcon = styled(Icon)`
@@ -18,7 +27,7 @@ export const ItemIcon = styled(Icon)`
   width: 1.5rem;
 `;
 
-export const ActionsContainer = styled.div`
+export const ActionsContainer = styled(Box)<BoxProps>`
   display: flex;
   align-items: center;
   gap: 0.5rem;
diff --git a/frontend/src/metabase/collections/components/PinnedItemCard/PinnedItemCard.tsx b/frontend/src/metabase/collections/components/PinnedItemCard/PinnedItemCard.tsx
index cb589ea326d4b7ed64b2008c3ea93ad2b26dfe37..2f5cf4d019ff30cce2661b62479f5b93f7b12340 100644
--- a/frontend/src/metabase/collections/components/PinnedItemCard/PinnedItemCard.tsx
+++ b/frontend/src/metabase/collections/components/PinnedItemCard/PinnedItemCard.tsx
@@ -11,7 +11,7 @@ import Tooltip from "metabase/core/components/Tooltip";
 import { getIcon } from "metabase/lib/icon";
 import { modelToUrl } from "metabase/lib/urls";
 import ModelDetailLink from "metabase/models/components/ModelDetailLink";
-import type { IconName } from "metabase/ui";
+import { Skeleton, type IconName } from "metabase/ui";
 import type Database from "metabase-lib/v1/metadata/Database";
 import type {
   Bookmark,
@@ -31,18 +31,30 @@ import {
   Title,
 } from "./PinnedItemCard.styled";
 
+type ItemOrSkeleton =
+  | {
+      /** If `item` is undefined, the `skeleton` prop must be true */
+      item: CollectionItem | RecentCollectionItem;
+      skeleton?: never;
+      iconForSkeleton?: never;
+    }
+  | {
+      item?: never;
+      skeleton: true;
+      iconForSkeleton: IconName;
+    };
+
 type Props = {
   databases?: Database[];
   bookmarks?: Bookmark[];
   createBookmark?: CreateBookmark;
   deleteBookmark?: DeleteBookmark;
   className?: string;
-  item: CollectionItem | RecentCollectionItem;
   collection?: Collection;
   onCopy?: (items: CollectionItem[]) => void;
   onMove?: (items: CollectionItem[]) => void;
   onClick?: () => void;
-};
+} & ItemOrSkeleton;
 
 const TOOLTIP_MAX_WIDTH = 450;
 
@@ -69,14 +81,15 @@ function PinnedItemCard({
   onCopy,
   onMove,
   onClick,
+  iconForSkeleton,
 }: Props) {
   const [showTitleTooltip, setShowTitleTooltip] = useState(false);
-  const icon = getIcon({
-    model: item.model,
-    moderated_status: item.moderated_status,
-  }).name;
-  const { description, name, model } = item;
-  const defaultedDescription = description || DEFAULT_DESCRIPTION[model] || "";
+  const icon =
+    iconForSkeleton ??
+    getIcon({
+      model: item.model,
+      moderated_status: item.moderated_status,
+    }).name;
 
   const maybeEnableTooltip = (
     event: MouseEvent<HTMLDivElement>,
@@ -90,21 +103,22 @@ function PinnedItemCard({
   };
 
   const hasActions =
+    item &&
     isCollectionItem(item) &&
     (onCopy || onMove || createBookmark || deleteBookmark || collection);
 
   return (
     <ItemLink
       className={className}
-      to={modelToUrl(item) ?? "/"}
+      to={item ? modelToUrl(item) ?? "/" : undefined}
       onClick={onClick}
     >
       <ItemCard flat>
         <Body>
           <Header>
             <ItemIcon name={icon as unknown as IconName} />
-            <ActionsContainer>
-              {item.model === "dataset" && <ModelDetailLink model={item} />}
+            <ActionsContainer h={item ? undefined : "2rem"}>
+              {item?.model === "dataset" && <ModelDetailLink model={item} />}
               {hasActions && (
                 <ActionMenu
                   databases={databases}
@@ -119,22 +133,30 @@ function PinnedItemCard({
               )}
             </ActionsContainer>
           </Header>
-          <Tooltip
-            tooltip={name}
-            placement="bottom"
-            maxWidth={TOOLTIP_MAX_WIDTH}
-            isEnabled={showTitleTooltip}
-          >
-            <Title
-              onMouseEnter={e => maybeEnableTooltip(e, setShowTitleTooltip)}
-            >
-              {name}
-            </Title>
-          </Tooltip>
-
-          <Description tooltipMaxWidth={TOOLTIP_MAX_WIDTH}>
-            {defaultedDescription}
-          </Description>
+          {item ? (
+            <>
+              <Tooltip
+                tooltip={item.name}
+                placement="bottom"
+                maxWidth={TOOLTIP_MAX_WIDTH}
+                isEnabled={showTitleTooltip}
+              >
+                <Title
+                  onMouseEnter={e => maybeEnableTooltip(e, setShowTitleTooltip)}
+                >
+                  {item.name}
+                </Title>
+              </Tooltip>
+              <Description tooltipMaxWidth={TOOLTIP_MAX_WIDTH}>
+                {item.description || DEFAULT_DESCRIPTION[item.model] || ""}
+              </Description>
+            </>
+          ) : (
+            <>
+              <Skeleton natural h="1.5rem" />
+              <Skeleton natural mt="xs" mb="4px" h="1rem" />
+            </>
+          )}
         </Body>
       </ItemCard>
     </ItemLink>
diff --git a/frontend/src/metabase/components/Badge/Badge.styled.tsx b/frontend/src/metabase/components/Badge/Badge.styled.tsx
index 11248f53a73bbb17a68836e6ef4e623e250352f4..4c4963e4fa7a131a70566550c7cfe2ff416eaa1b 100644
--- a/frontend/src/metabase/components/Badge/Badge.styled.tsx
+++ b/frontend/src/metabase/components/Badge/Badge.styled.tsx
@@ -9,12 +9,12 @@ import { Icon } from "metabase/ui";
 
 interface RawMaybeLinkProps {
   to?: string;
-  activeColor: string;
-  inactiveColor: string;
-  isSingleLine: boolean;
+  activeColor?: string;
+  inactiveColor?: string;
+  isSingleLine?: boolean;
 }
 
-function RawMaybeLink({
+export function RawMaybeLink({
   to,
   activeColor,
   inactiveColor,
@@ -26,7 +26,7 @@ function RawMaybeLink({
 
 const hoverStyle = (props: RawMaybeLinkProps) => css`
   cursor: pointer;
-  color: ${color(props.activeColor)};
+  ${props.activeColor ? `color: ${color(props.activeColor)};` : ""}
 `;
 
 export const MaybeLink = styled(RawMaybeLink)`
@@ -34,7 +34,8 @@ export const MaybeLink = styled(RawMaybeLink)`
   align-items: center;
   font-size: 0.875em;
   font-weight: bold;
-  color: ${props => color(props.inactiveColor)};
+  ${props =>
+    props.inactiveColor ? `color: ${color(props.inactiveColor)};` : ""}
   min-width: ${props => (props.isSingleLine ? 0 : "")};
 
   :hover {
diff --git a/frontend/src/metabase/components/ItemsTable/BaseItemsTable.styled.tsx b/frontend/src/metabase/components/ItemsTable/BaseItemsTable.styled.tsx
index 227120a49841c5635ce6c3e1299d76f31fe7dbf2..f24b11e68086beab599ae7f984f1474b4985abe5 100644
--- a/frontend/src/metabase/components/ItemsTable/BaseItemsTable.styled.tsx
+++ b/frontend/src/metabase/components/ItemsTable/BaseItemsTable.styled.tsx
@@ -10,6 +10,8 @@ import BaseModelDetailLink from "metabase/models/components/ModelDetailLink";
 import type { TextProps } from "metabase/ui";
 import { Text, FixedSizeIcon } from "metabase/ui";
 
+import { RawMaybeLink } from "../Badge/Badge.styled";
+
 import type { ResponsiveProps } from "./utils";
 import { getContainerQuery } from "./utils";
 
@@ -96,15 +98,17 @@ export const ItemButton = styled(Text)<
 
 export const ItemLink = styled(Link)(itemLinkStyle);
 
+export const MaybeItemLink = styled(RawMaybeLink)(itemLinkStyle);
+
 export const ItemNameCell = styled.td`
   padding: 0 !important;
 
-  ${ItemLink}, ${ItemButton} {
+  ${ItemLink}, ${MaybeItemLink}, ${ItemButton} {
     padding: 1em;
   }
 
   &:hover {
-    ${ItemLink}, ${ItemButton} {
+    ${ItemLink}, ${MaybeItemLink}, ${ItemButton} {
       color: var(--mb-color-brand);
     }
 
diff --git a/frontend/src/metabase/components/Schedule/utils.tsx b/frontend/src/metabase/components/Schedule/utils.tsx
index d38558955b969a49128c4288cbbe53ed5bf6d421..1a428c18d86d875544c00e25a4137c0cbcf1c20c 100644
--- a/frontend/src/metabase/components/Schedule/utils.tsx
+++ b/frontend/src/metabase/components/Schedule/utils.tsx
@@ -65,3 +65,5 @@ export const getLongestSelectLabel = (data: SelectProps["data"]) =>
     const label = typeof option === "string" ? option : option.label || "";
     return label.length > acc.length ? label : acc;
   }, "");
+
+// HIIII
diff --git a/frontend/src/metabase/ui/components/feedback/Skeleton/Repeat.tsx b/frontend/src/metabase/ui/components/feedback/Skeleton/Repeat.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..cc2bf2a1d4c7ba49845a7a9a2a340909c8904aaf
--- /dev/null
+++ b/frontend/src/metabase/ui/components/feedback/Skeleton/Repeat.tsx
@@ -0,0 +1,20 @@
+import { type PropsWithChildren, isValidElement } from "react";
+import { cloneElement } from "react";
+
+export const Repeat = ({
+  times,
+  /** Must be a valid React element */
+  children,
+}: PropsWithChildren<{
+  times: number;
+}>) => {
+  if (!isValidElement(children)) {
+    return null;
+  }
+  return Array.from({ length: times }).map((_, index) => {
+    const props = { key: `${index}` };
+    if (isValidElement(children)) {
+      return cloneElement(children, props);
+    }
+  });
+};
diff --git a/frontend/src/metabase/ui/components/feedback/Skeleton/Skeleton.styled.tsx b/frontend/src/metabase/ui/components/feedback/Skeleton/Skeleton.styled.tsx
index 7f3079f1062171bf99b39a9adc2e35893054d62d..ff228d12c129cbf600fba874fbdea2e841348e3b 100644
--- a/frontend/src/metabase/ui/components/feedback/Skeleton/Skeleton.styled.tsx
+++ b/frontend/src/metabase/ui/components/feedback/Skeleton/Skeleton.styled.tsx
@@ -1,18 +1,33 @@
-import type { MantineThemeOverride } from "@mantine/core";
+import { keyframes, type MantineThemeOverride } from "@mantine/core";
 
-export const getSkeletonOverrides = (): MantineThemeOverride["components"] => ({
-  Skeleton: {
-    styles: _theme => {
-      return {
-        root: {
-          "&::before": {
-            background: "transparent !important",
-          },
-          "&::after": {
-            background: "var(--mb-color-border) !important",
+const shimmerAnimation = keyframes`
+0% {
+  transform: translateX(-100%);
+}
+100% {
+  transform: translateX(100%);
+}
+`;
+
+export const getSkeletonOverrides = (): MantineThemeOverride["components"] => {
+  return {
+    Skeleton: {
+      styles: _theme => {
+        return {
+          // We replace Mantine's pulsing animation with a shimmer animation
+          root: {
+            "background-color": "rgba(0, 0, 0, .03)",
+            "&::before": {
+              background:
+                "linear-gradient(100deg, transparent, rgba(0, 0, 0, .03) 50%, transparent) ! important",
+              animation: `${shimmerAnimation} 1.4s linear infinite`,
+            },
+            "&::after": {
+              display: "none",
+            },
           },
-        },
-      };
+        };
+      },
     },
-  },
-});
+  };
+};
diff --git a/frontend/src/metabase/ui/components/feedback/Skeleton/Skeleton.tsx b/frontend/src/metabase/ui/components/feedback/Skeleton/Skeleton.tsx
index 3f3b368cbffe5a1f555e49abbf61b90c3d8de2f7..31f6094225d0b9b37da6dfadd857a3d1b4aff2ec 100644
--- a/frontend/src/metabase/ui/components/feedback/Skeleton/Skeleton.tsx
+++ b/frontend/src/metabase/ui/components/feedback/Skeleton/Skeleton.tsx
@@ -1,3 +1,19 @@
-export type { SkeletonProps } from "@mantine/core";
-export { Skeleton } from "@mantine/core";
-export { getSkeletonOverrides } from "./Skeleton.styled";
+import type { SkeletonProps } from "@mantine/core";
+import { Skeleton as MantineSkeleton } from "@mantine/core";
+import { useMemo } from "react";
+
+export const Skeleton = ({
+  natural,
+  ...props
+}: SkeletonProps & {
+  /** Automatically assign a natural-looking, random width to the skeleton */
+  natural?: boolean;
+}) => {
+  const width = useMemo(
+    () => (natural ? `${Math.random() * 30 + 50}%` : props.width),
+    [natural, props.width],
+  );
+  return <MantineSkeleton width={width} {...props} />;
+};
+
+export type { SkeletonProps };
diff --git a/frontend/src/metabase/ui/components/feedback/Skeleton/index.ts b/frontend/src/metabase/ui/components/feedback/Skeleton/index.ts
index ad05c7df1139aa9628e69df17d7f3974a6316f48..6b2896a49b5b39753018cd7287ecf838f3412dc6 100644
--- a/frontend/src/metabase/ui/components/feedback/Skeleton/index.ts
+++ b/frontend/src/metabase/ui/components/feedback/Skeleton/index.ts
@@ -1,2 +1,2 @@
-export { Skeleton } from "@mantine/core";
+export { Skeleton } from "./Skeleton";
 export * from "./Skeleton.styled";