Skeleton
Display a placeholder while content is loading.
import { Circle, HStack, Stack } from 'styled-system/jsx'
import { Skeleton } from '~/components/ui/skeleton'
export const Demo = () => {
return (
<HStack width="full" gap="4">
<Skeleton borderRadius="full">
<Circle size="20" />
</Skeleton>
<Stack gap="3.5" width="full">
<Skeleton h="4" />
<Skeleton h="4" width="80%" />
<Skeleton h="4" width="60%" />
</Stack>
</HStack>
)
}
import { Circle, HStack, Stack } from 'styled-system/jsx'
import { Skeleton } from '~/components/ui/skeleton'
export const Demo = () => {
return (
<HStack width="full" gap="4">
<Skeleton borderRadius="full">
<Circle size="20" />
</Skeleton>
<Stack gap="3.5" width="full">
<Skeleton h="4" />
<Skeleton h="4" width="80%" />
<Skeleton h="4" width="60%" />
</Stack>
</HStack>
)
}
Usage
import { Skeleton } from '~/components/ui/skeleton'
Examples
You can use it as a standalone component or wrap it around other components.
contents wrapped
won't be visible
<Skeleton>
<div>contents wrapped</div>
<div>won't be visible</div>
</Skeleton>
Skipping the animation
You can prevent the Skeleton
from rendering using the isLoaded
prop.
https://park-ui.com
<Skeleton isLoaded>
<span>https://park-ui.com</span>
</Skeleton>
Installation
npx @park-ui/cli components add skeleton
1
Add Styled Primitive
Copy the code snippet below into ~/components/ui/styled/skeleton.tsx
'use client'
import type { Assign, HTMLArkProps } from '@ark-ui/react'
import { ark } from '@ark-ui/react/factory'
import { forwardRef } from 'react'
import { styled } from 'styled-system/jsx'
import { type SkeletonVariantProps, skeleton } from 'styled-system/recipes'
import type { JsxStyleProps } from 'styled-system/types'
const StyledSkeleton = styled(ark.div, skeleton)
export interface SkeletonProps
extends Assign<JsxStyleProps, HTMLArkProps<'div'>>,
SkeletonVariantProps {
/**
*
* @default false
*/
isLoaded?: boolean
}
export const Skeleton = forwardRef<HTMLDivElement, SkeletonProps>((props, ref) => {
const { isLoaded, ...otherProps } = props
if (isLoaded) {
return <styled.div animation="fade-in" ref={ref} {...otherProps} />
}
return <StyledSkeleton ref={ref} {...otherProps} />
})
Skeleton.displayName = 'Skeleton'
import type { Assign, HTMLArkProps } from '@ark-ui/solid'
import { Show, splitProps } from 'solid-js'
import { styled } from 'styled-system/jsx'
import { type SkeletonVariantProps, skeleton } from 'styled-system/recipes'
import type { JsxStyleProps } from 'styled-system/types'
const StyledSkeleton = styled('div', skeleton)
export interface SkeletonProps
extends Assign<JsxStyleProps, HTMLArkProps<'div'>>,
SkeletonVariantProps {
/**
* @default false
*/
isLoaded?: boolean
}
export const Skeleton = (props: SkeletonProps) => {
const [localProps, otherProps] = splitProps(props, ['isLoaded'])
return (
<Show when={localProps.isLoaded} fallback={<StyledSkeleton {...otherProps} />}>
<styled.div animation="fade-in" {...otherProps} />
</Show>
)
}
No snippet found
2
Add Re-Export
To improve the developer experience, re-export the styled primitives in~/components/ui/skeleton.tsx
.
export { Skeleton, type SkeletonProps } from './styled/skeleton'
export { Skeleton, type SkeletonProps } from './styled/skeleton'
3
Integrate Recipe
If you're not using @park-ui/preset
, add the following recipe to yourpanda.config.ts
:
import { defineRecipe } from '@pandacss/dev'
export const skeleton = defineRecipe({
className: 'skeleton',
base: {
animation: 'skeleton-pulse',
backgroundClip: 'padding-box',
backgroundColor: 'gray.a4',
borderRadius: 'l3',
color: 'transparent',
cursor: 'default',
pointerEvents: 'none',
userSelect: 'none',
'&::before, &::after, *': {
visibility: 'hidden',
},
},
})