Components
Skeleton

Skeleton

Display a placeholder while content is loading.

Usage

import { Circle, HStack, Stack } from 'styled-system/jsx'
import { Skeleton, type SkeletonProps } from '~/components/ui/skeleton'

export const Demo = (props: SkeletonProps) => {
  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

1

Add Component

Insert code snippet into your project. Update import paths as needed.

import { ark } from '@ark-ui/react/factory'
import { forwardRef, type ReactNode } from 'react'
import { styled, type HTMLStyledProps } from 'styled-system/jsx'
import { skeleton } from 'styled-system/recipes'

const StyledSkeleton = styled(ark.div, skeleton)

export interface SkeletonProps extends HTMLStyledProps<'div'> {
  children?: ReactNode
  /**
   *
   * @default false
   */
  isLoaded?: boolean
}

export const Skeleton = forwardRef<HTMLDivElement, SkeletonProps>((props, ref) => {
  const { isLoaded, ...rest } = props

  if (isLoaded) {
    return <styled.div animation="fade-in" ref={ref} {...rest} />
  }
  return <StyledSkeleton ref={ref} {...rest} />
})

Skeleton.displayName = 'Skeleton'
2

Add Recipe

This step is necessary only if you do not use any of the Park UI plugins.

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',
    },
  },
})

Previous

Select