Skeleton
Display a placeholder while content is loading.
Usage
import { Circle, HStack, Stack } from 'styled-system/jsx'
import { Skeleton } from '~/components/ui'
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>
  )
}
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 skeleton1
Styled Primitive
Copy the code snippet below into ~/components/ui/primitives/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 foundExtend ~/components/ui/primitives/index.ts with the following line:
export { Skeleton, type SkeletonProps } from './skeleton'2
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',
    },
  },
})