Skip to content
Twilight React Playground
ثيم رائدaren

ProductsSlider

componentBeginnerserverbrowserlive demo

A carousel block that loads products from a source you name (latest, offers, a category…) and draws a ProductCard for each.

import { ProductsSlider } from '@salla.sa/twilight-theme-engine/components/home';

In plain words

You do not hand this block any products. You tell it where they come from, products: { source: 'latest' }, and it asks the Salla API for them itself, then shows them in a sliding row with an optional title and a "View All" link.

Every setting goes in one prop called data, because that is how the merchant's home page arrives from the API: one object per block. The engine's product page uses this same block for "similar products".

Signature

function ProductsSlider(props: {
  data: {
    products: { source: ProductsListSource; source_value?: number | number[] | null };
    title?: string;
    display_all_url?: string;   // empty or missing: no "View All" link
    position?: number;          // 1: part of the element ids
    priority?: boolean;         // eager images for the first two cards
    show_controls?: boolean;
    controls_outer?: boolean;
    loop?: boolean;
    centered?: boolean;
    slides_per_view?: number | 'auto';
    direction?: 'rtl' | 'ltr';
    autoplay?: boolean;
    [key: string]: unknown;
  };
}): JSX.Element

Try it live

A product carousel that loads its own products. You name the source; the block fetches, then draws a ProductCard per product.Try this: switch the source: the block shows its skeleton and fetches again. A source with no products renders nothing, title included.
Storefront canvas · ar · RTL
Controls
Empty hides the "View All" link.
autoplay
loop
show_controls
What a theme writes
import { ProductsSlider } from '@salla.sa/twilight-theme-engine/components/home';

export function NewArrivals() {
  return (
    <ProductsSlider
      data={{
        products: { source: 'latest' },
        title: 'New arrivals',
        display_all_url: '/products',
        show_controls: true,
      }}
    />
  );
}

Example

app/components/home/NewArrivals.tsx
import { ProductsSlider } from '@salla.sa/twilight-theme-engine/components/home';

export function NewArrivals() {
  return (
    <ProductsSlider
      data={{
        products: { source: 'latest' },
        title: 'New arrivals',
        display_all_url: '/latest-products',
        autoplay: true,
      }}
    />
  );
}

How it behaves

  • It calls product.list({ source, sourceValue }) from @salla.sa/twilight-theme-engine/api/product (no perPage, so 16 products) inside SallaProductsSlider, in an effect. The server render shows the products skeleton; products arrive in the browser. It is not a TanStack Query, so nothing is cached or dehydrated, and each mount fetches again.

  • ProductsListSource (from /api/product) is latest, offers, top-rated, best_selling, categories, brands, tags, selected, related, wishlist, recently, search and a few more. source_value carries the ids the source needs, as an array such as [708738657] for a category.

  • Slider options are forwarded only when set, so the slider keeps its own defaults otherwise. The "View All" label is the translation blocks.home.display_all.

  • priority is read from inside data, which is where HomeComponentRenderer puts it for the first three blocks of the home page.

  • Not lazy, despite the Lazy* names in the engine source: no <Suspense> of yours is needed.

Gotchas

  • A source with no products renders nothing at all, title included (SallaProductsSlider returns null for an empty list). Plan the page for a missing block.

  • The fetch reruns whenever its loader changes, and the loader depends on products.source_value. An array written inline, source_value: [1, 2], is a new array on every render of the parent, so every parent render fetches again. Keep such data at module scope or in useMemo.

  • Element ids come from position (best-offers-<position>-slider, slider-<position>). Two sliders with the same position on one page share ids; give each its own.

Related

Source and docs