Skeleton Loader
A shimmering placeholder shown while content is loading.
A shimmering placeholder shown while content is loading. Compose it from the exported registry parts so local content and behaviour stay in the application while the visual contract stays token-driven.
newt-skeletonimport { Skeleton } from "@/registry/bases/newt/ui/skeleton"
export default function SkeletonDemo() {
return (
<div className="flex w-full max-w-sm gap-3">
<Skeleton variant="avatar" />
<div className="flex flex-1 flex-col gap-1.5">
<Skeleton variant="title" />
<Skeleton variant="text" className="w-[80%]" />
</div>
</div>
)
}<script setup lang="ts">
import { Skeleton } from "~~/registry/bases/newt/ui/skeleton"
</script>
<template>
<div class="flex w-full max-w-sm gap-3">
<Skeleton variant="avatar" />
<div class="flex flex-1 flex-col gap-1.5">
<Skeleton variant="title" />
<Skeleton variant="text" class="w-[80%]" />
</div>
</div>
</template>Installation
pnpm dlx newtui@latest add skeletonnpx newtui@latest add skeletonyarn dlx newtui@latest add skeletonbunx newtui@latest add skeletonInstall the dependencies
pnpm dlx --yes class-variance-authoritynpx --yes class-variance-authorityyarn dlx --yes class-variance-authoritybunx --yes class-variance-authorityCopy the source into your project
import { cva, type VariantProps } from "class-variance-authority"
import * as React from "react"
import { cn } from "@/lib/utils"
const skeletonVariants = cva(
"animate-[newt-skeleton-shimmer_1.6s_ease-in-out_infinite] rounded-sm bg-[linear-gradient(90deg,var(--newt-bg-elevated)_25%,var(--newt-bg-hover)_50%,var(--newt-bg-elevated)_75%)] bg-[length:200%_100%] motion-reduce:animate-none motion-reduce:opacity-60",
{
variants: {
variant: {
default: "",
text: "h-[14px]",
avatar: "h-10 w-10 rounded-full",
title: "h-5 w-[40%]",
},
},
defaultVariants: {
variant: "default",
},
}
)
export interface SkeletonProps
extends React.ComponentProps<"div">, VariantProps<typeof skeletonVariants> {}
const Skeleton = React.forwardRef<HTMLDivElement, SkeletonProps>(
({ className, variant, ...props }, ref) => (
<>
<style>{`@keyframes newt-skeleton-shimmer{0%{background-position:200% 0}100%{background-position:-200% 0}}`}</style>
<div
ref={ref}
aria-hidden="true"
data-variant={variant ?? "default"}
className={cn(skeletonVariants({ variant }), className)}
{...props}
/>
</>
)
)
Skeleton.displayName = "Skeleton"
export { Skeleton, skeletonVariants }<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { cn } from "@/lib/utils"
import { skeletonVariants, type SkeletonVariants } from "."
const props = defineProps<{
class?: HTMLAttributes["class"]
variant?: SkeletonVariants["variant"]
}>()
</script>
<template>
<div
aria-hidden="true"
:data-variant="props.variant ?? 'default'"
:class="cn(skeletonVariants({ variant: props.variant }), props.class)"
/>
</template>
<style>
@keyframes newt-skeleton-shimmer {
0% {
background-position: 200% 0;
}
100% {
background-position: -200% 0;
}
}
</style>import { cva, type VariantProps } from "class-variance-authority"
export { default as Skeleton } from "./Skeleton.vue"
export const skeletonVariants = cva(
"animate-[newt-skeleton-shimmer_1.6s_ease-in-out_infinite] rounded-sm bg-[linear-gradient(90deg,var(--newt-bg-elevated)_25%,var(--newt-bg-hover)_50%,var(--newt-bg-elevated)_75%)] bg-[length:200%_100%] motion-reduce:animate-none motion-reduce:opacity-60",
{
variants: {
variant: {
default: "",
text: "h-[14px]",
avatar: "h-10 w-10 rounded-full",
title: "h-5 w-[40%]",
},
},
defaultVariants: {
variant: "default",
},
}
)
export type SkeletonVariants = VariantProps<typeof skeletonVariants>Update the import paths
The files import @/lib/utils and sibling components through the aliases in your components.json. Point them at wherever those live in your project.
Usage
import { Skeleton } from "@/components/ui/skeleton"
export function Example() {
return <Skeleton />
}<script setup lang="ts">
import { Skeleton } from "@/components/ui/skeleton"
</script>
<template>
<Skeleton />
</template>API reference
Skeleton
children / default slot?React.ReactNode / Vue slot
Content rendered inside the component.
React.ReactNode / Vue slotclassName / class?string
Additional classes merged with the component defaults.
stringThe registry exports Skeleton. Parts without a table accept the native attributes for the element they render; React uses className, while Vue uses class and fallthrough attributes.
Accessibility
Preserve the native semantics of the rendered elements and pass through ARIA attributes when the surrounding context needs a label or description. Any interactive child needs a visible focus indicator, and meaning must not rely on colour alone.
Tokens
Skeleton Loader reads its colours, radii and motion from the --newt-* tokens installed with the library. Override a token and every component that reads it follows, including this one — see the token layer. In the plain HTML and CSS distribution the same component is newt-skeleton.