{showcases.map(({ showcase, user }) => (
diff --git a/src/components/ds/ds-nav.ts b/src/components/ds/ds-nav.ts
index 027387d0b..d0e91ccfc 100644
--- a/src/components/ds/ds-nav.ts
+++ b/src/components/ds/ds-nav.ts
@@ -226,6 +226,16 @@ export const dsNav: Array = [
to: '/ds/partner-rail',
sections: ['Rail', 'Tiers', 'Per-logo scale'],
},
+ {
+ label: 'Skeleton',
+ to: '/ds/skeleton',
+ sections: [
+ 'Skeleton',
+ 'On any surface',
+ 'Grouping and accessibility',
+ 'Match the real layout',
+ ],
+ },
{
label: 'Spinner',
to: '/ds/spinner',
diff --git a/src/components/ds/ui/index.tsx b/src/components/ds/ui/index.tsx
index 7557cc96c..2b7f416cc 100644
--- a/src/components/ds/ui/index.tsx
+++ b/src/components/ds/ui/index.tsx
@@ -628,6 +628,60 @@ export function Spinner({ className }: { className?: string }) {
)
}
+/* --------------------------------------------------------------- Skeleton -- */
+
+/**
+ * Placeholder block shown while content loads.
+ *
+ * The tint is an alpha overlay rather than an opaque surface token, so it always
+ * reads lighter than whatever sits behind it in dark mode and darker in light.
+ * An opaque `background-subtle` cannot do that: in dark mode it is lighter than
+ * the page but darker than an elevated card, so it inverts as it moves between
+ * surfaces.
+ *
+ * The pulse is wrapped in `motion-safe:` so it holds still under
+ * `prefers-reduced-motion`.
+ */
+export function Skeleton({
+ className,
+ ...rest
+}: React.ComponentPropsWithoutRef<'div'>) {
+ return (
+
+ )
+}
+
+/**
+ * Wrapper that announces a loading region to assistive tech. Wrap a group of
+ * `Skeleton` blocks in this so screen readers hear one message instead of
+ * nothing — the blocks themselves are `aria-hidden`.
+ */
+export function SkeletonGroup({
+ label = 'Loading',
+ className,
+ children,
+ ...rest
+}: React.ComponentPropsWithoutRef<'div'> & { label?: string }) {
+ return (
+
+ {children}
+
+ )
+}
+
/* ----------------------------------------------------------------- Avatar -- */
type AvatarSize = '2xs' | 'xs' | 'sm' | 'md' | 'lg' | 'xl'
diff --git a/src/components/home/HomeCommunitySection.tsx b/src/components/home/HomeCommunitySection.tsx
index 16d7589c7..b91f10c48 100644
--- a/src/components/home/HomeCommunitySection.tsx
+++ b/src/components/home/HomeCommunitySection.tsx
@@ -4,7 +4,7 @@ import { visible } from '@tanstack/react-start/hydration'
import { ArrowRightIcon } from '@phosphor-icons/react'
import { MaintainerCard } from '~/components/MaintainerCard'
import { coreMaintainers } from '~/libraries/maintainers'
-import { Button } from '~/components/ds/ui'
+import { Button, Skeleton, SkeletonGroup } from '~/components/ds/ui'
export function HomeCommunitySection() {
return (
@@ -19,19 +19,19 @@ export function HomeCommunitySection() {
function CommunitySkeleton() {
return (
-