shimmer-from-structure

repository·main·Indexed 22 days ago

https://github.com/darula-hpp/shimmer-from-structure

A universal UI skeleton generator for React, Vue, Svelte, Angular, and SolidJS. It automatically creates responsive shimmer states by measuring actual UI components at runtime, eliminating the need for manual skeleton maintenance. Features include support for dynamic content via templateProps, automatic border-radius detection, and seamless integration with React Suspense.

Tokens
13.1K
Snippets
57
Records
71
Agent score
77%

What's inside shimmer-from-structure

  1. Performance characteristics of Shimmer From Structure

    main

    Shimmer From Structure is designed for high performance and minimal visual disruption:

    • Synchronous Measurement: Uses useLayoutEffect to ensure DOM measurements happen synchronously, preventing visual flicker during the transition to the loading state.
    • Triggered Measurement: Measurement logic only executes when the loading state changes to true.
    • Efficient Re-renders: The library minimizes re-renders, only updating when the loading state or the component children change.
    • Lightweight: Uses native browser APIs for DOM measurements to keep the footprint small.
  2. How Shimmer From Structure works

    main

    Shimmer From Structure generates loading skeletons by measuring the actual DOM structure of your components.

    The Lifecycle:

    1. Visible Container Rendering: When loading={true}, the component renders with transparent text but visible container backgrounds.
    2. Template Props Injection: If templateProps is provided, these props are spread onto the first child, allowing dynamic components to render with mock data.
    3. DOM Measurement: The library uses useLayoutEffect to synchronously measure all leaf elements via getBoundingClientRect().
    4. Border Radius Detection: It automatically captures the computed border-radius from CSS (e.g., for circular avatars).
    5. Shimmer Generation: It creates absolutely-positioned shimmer blocks that match the measured dimensions.
    6. Animation: A smooth gradient animation sweeps across each block.

    Key Features:

    • Container backgrounds visible: Uses color: transparent instead of opacity: 0 so card backgrounds and borders remain visible during loading.
    • Auto border-radius: Automatically matches the shape of elements.
    • Fallback radius: Uses fallbackBorderRadius for elements like text that typically have border-radius: 0 to avoid sharp edges.
    • Dark-mode friendly: Uses semi-transparent whites by default.
  3. Use templateProps for dynamic content

    main

    When your component relies on dynamic props (e.g., data fetched from an API), the shimmer needs mock data to measure the correct layout dimensions. Use the templateProps prop to pass this mock data. The templateProps object is spread onto the first child component when loading is true, allowing it to render with the provided mock data for measurement.

    import { Shimmer } from 'shimmer-from-structure';
    
    const UserCard = ({ user }) => (
      <div className="card">
        <img src={user.avatar} className="avatar" />
        <h2>{user.name}</h2>
        <p>{user.role}</p>
      </div>
    );
    
    const userTemplate = {
      name: 'Loading...',
      role: 'Loading role...',
      avatar: 'placeholder.jpg',
    };
    
    function App() {
      const [loading, setLoading] = useState(true);
      const [user, setUser] = useState(null);
    
      return (
        <Shimmer loading={loading} templateProps={{ user: userTemplate }}>
          <UserCard user={user || userTemplate} />
        </Shimmer>
      );
    }
  4. Develop with the Shimmer From Structure monorepo

    main

    If you are contributing to the repository, you can manage the monorepo using npm workspaces. Use the following commands to build or test the packages:

    # Install dependencies
    npm install
    
    # Build all packages
    npm run build
    
    # Build individual packages
    npm run build:core
    npm run build:react
    npm run build:vue
    npm run build:svelte
    npm run build:main
    
    # Run tests
    npm test
  5. Install shimmer-from-structure

    main

    You can install the core package using your preferred package manager. Note that while the main package supports React, other frameworks require their specific adapter packages.

    npm install shimmer-from-structure
    # or
    yarn add shimmer-from-structure
    # or
    pnpm add shimmer-from-structure
  6. Migrate Svelte projects from v1.x to v2.0.0

    main

    Version 2.0.0 introduces a breaking change by migrating the Svelte adapter to Svelte 5. Svelte 4 is no longer supported. If you cannot upgrade to Svelte 5, you must pin your dependency to v1.x using @shimmer-from-structure/svelte@^1.1.0.

    Migration Steps

    1. Update dependencies to support Svelte 5:

      npm install svelte@^5.0.0 @sveltejs/vite-plugin-svelte@^4.0.0 svelte-check@^4.0.0
    2. Update App mounting in your main.ts to use the new mount API:

      import { mount } from 'svelte';
      import App from './App.svelte';
      
      mount(App, { target: document.getElementById('app')! });
    3. Update components to use Svelte 5 Runes (recommended):

      • Replace export let prop with let { prop } = $props().
      • Replace let x = value with let x = $state(value).
      • Replace $: derived = ... with const derived = $derived(...).
      • Replace $: { ... } with $effect(() => { ... }).
    npm install svelte@^5.0.0 @sveltejs/vite-plugin-svelte@^4.0.0 svelte-check@^4.0.0
  7. Migrate React projects from v0.7.0 to v1.0.0

    main

    The migration from v0.7.0 to v1.0.0 is seamless for React users. The library moved to a monorepo structure, but the main shimmer-from-structure package continues to re-export the React adapter for backward compatibility.

    Migration Steps

    1. Update the package:

      npm update shimmer-from-structure
    2. Verify Imports: Your existing imports will continue to work without changes:

      import { Shimmer, ShimmerProvider } from 'shimmer-from-structure';

    Optional: Use Explicit Imports

    For better clarity, you may choose to import directly from the React adapter package:

    import { Shimmer, ShimmerProvider } from '@shimmer-from-structure/react';
    npm update shimmer-from-structure
  8. Best practices for using Shimmer

    main

    To get the best visual results and performance from Shimmer From Structure, follow these guidelines:

    1. Use templateProps for Dynamic Data: Always provide templateProps with mock data that matches the expected structure of your real component. This ensures the shimmer layout matches the final UI.
    2. Match Template Structure: Ensure your template data has the same array length and property structure as real data.
    3. Use Individual Shimmer Components: Wrap each section in its own Shimmer component to allow for independent loading states. Avoid wrapping multiple unrelated sections in a single Shimmer with an OR condition (e.g., loading={loadingUsers || loadingPosts}).
    4. Consider Element Widths: For text elements like <h1> or <p>, use width: fit-content; in your CSS if you want the shimmer to match the text width rather than the full container width.
    5. Provide Container Dimensions: For asynchronous components like charts, ensure the containers have explicit dimensions so the library has something to measure.