FreeMIT LicenseNewFeatured

Hangline — 3D Clothing Store Product Carousel for React, with Sizes, Bag & Accessory Tray

An endless 3D clothing rail for fashion stores in React: garments hang in true perspective, the piece in front faces you, and sizes, add to bag, a detail view and an accessory tray sit beside it. CSS 3D, no 3D library, light and dark.

by UpFork, built by Ramin ValadanComponentUpdated 14 Nov 2026

2 articles about itBehind the build40 lessons
Watch0
Preview of Hangline — 3D Clothing Store Product Carousel for React, with Sizes, Bag & Accessory Tray

Code

18 files · 224 assets

// Written by scripts/photos/export.py from scripts/photos/catalogue.json and the pictures found in the
// source folder. Do not edit by hand: change the catalogue or the pictures and run the pipeline again.
// A piece with standIn shows another slot's pictures and data until its own pictures exist.
import type { Accessory } from "../hangline/types";

export const accessories: (Accessory & { standIn?: string })[] = [
  {
    "id": "a01",
    "slug": "pellow-bucket-hat",
    "href": "/pieces/pellow-bucket-hat",
    "name": "Pellow bucket hat",
    "price": 35,
    "currency": "EUR",
    "description": "Soft wide-wale corduroy with a stitched brim.",
    "photo": {
      "src": "https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a01-top-960.webp",
      "srcSet": "https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a01-top-480.webp 480w, https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a01-top-960.webp 960w, https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a01-top-1600.webp 1600w",
      "width": 1600,
      "height": 1600,
      "shadow": "https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a01-shadow.webp",
      "alt": "Pellow bucket hat, from above"
    },
    "place": {"x": 0.2, "y": 0.3, "rotation": -8},
    "gallery": [
      {
        "kind": "detail",
        "src": "https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a01-top-960.webp",
        "srcSet": "https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a01-top-480.webp 480w, https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a01-top-960.webp 960w, https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a01-top-1600.webp 1600w",
        "width": 1600,
        "height": 1600,
        "alt": "Pellow bucket hat, from above"
      },
      {
        "kind": "detail",
        "src": "https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a01-close-960.webp",
        "srcSet": "https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a01-close-480.webp 480w, https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a01-close-960.webp 960w, https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a01-close-1600.webp 1600w",
        "width": 1600,
        "height": 1600,
        "alt": "Pellow bucket hat, up close"
      }
    ],
    "variants": {"label": "Size", "options": [{"label": "S/M", "stock": 6}, {"label": "M/L", "stock": 4}]}
  },
  {
    "id": "a02",
    "slug": "linko-chunky-chain",
    "href": "/pieces/linko-chunky-chain",
    "name": "Linko chunky chain",
    "price": 45,
    "currency": "EUR",
    "description": "Heavy curb links in polished steel, with a plain clasp.",
    "photo": {
      "src": "https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a02-top-768.webp",
      "srcSet": "https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a02-top-480.webp 480w, https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a02-top-768.webp 768w",
      "width": 768,
      "height": 768,
      "shadow": "https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a02-shadow.webp",
      "alt": "Linko chunky chain, from above"
    },
    "place": {"x": 0.5, "y": 0.28, "rotation": 4},
    "gallery": [
      {
        "kind": "detail",
        "src": "https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a02-top-768.webp",
        "srcSet": "https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a02-top-480.webp 480w, https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a02-top-768.webp 768w",
        "width": 768,
        "height": 768,
        "alt": "Linko chunky chain, from above"
      },
      {
        "kind": "detail",
        "src": "https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a02-close-960.webp",
        "srcSet": "https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a02-close-480.webp 480w, https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a02-close-960.webp 960w, https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a02-close-1024.webp 1024w",
        "width": 1024,
        "height": 1024,
        "alt": "Linko chunky chain, up close"
      }
    ],
    "variants": {"label": "Length", "options": [{"label": "45 cm", "stock": 5}, {"label": "50 cm", "stock": 3}]}
  },
  {
    "id": "a03",
    "slug": "juxa-sling-bag",
    "href": "/pieces/juxa-sling-bag",
    "name": "Juxa sling bag",
    "price": 49,
    "currency": "EUR",
    "description": "A small nylon crossbody with one zip pocket and an adjustable strap.",
    "photo": {
      "src": "https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a03-top-732.webp",
      "srcSet": "https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a03-top-480.webp 480w, https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a03-top-732.webp 732w",
      "width": 732,
      "height": 732,
      "shadow": "https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a03-shadow.webp",
      "alt": "Juxa sling bag, from above"
    },
    "place": {"x": 0.8, "y": 0.32, "rotation": 6},
    "gallery": [
      {
        "kind": "detail",
        "src": "https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a03-top-732.webp",
        "srcSet": "https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a03-top-480.webp 480w, https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a03-top-732.webp 732w",
        "width": 732,
        "height": 732,
        "alt": "Juxa sling bag, from above"
      },
      {
        "kind": "detail",
        "src": "https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a03-close-960.webp",
        "srcSet": "https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a03-close-480.webp 480w, https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a03-close-960.webp 960w, https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a03-close-1024.webp 1024w",
        "width": 1024,
        "height": 1024,
        "alt": "Juxa sling bag, up close"
      }
    ]
  },
  {
    "id": "a04",
    "slug": "brimo-washed-cap",
    "href": "/pieces/brimo-washed-cap",
    "name": "Brimo washed cap",
    "price": 29,
    "currency": "EUR",
    "description": "Washed cotton twill with a curved brim and a plain back strap.",
    "photo": {
      "src": "https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a04-top-758.webp",
      "srcSet": "https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a04-top-480.webp 480w, https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a04-top-758.webp 758w",
      "width": 758,
      "height": 758,
      "shadow": "https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a04-shadow.webp",
      "alt": "Brimo washed cap, from above"
    },
    "place": {"x": 0.22, "y": 0.74, "rotation": 10},
    "gallery": [
      {
        "kind": "detail",
        "src": "https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a04-top-758.webp",
        "srcSet": "https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a04-top-480.webp 480w, https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a04-top-758.webp 758w",
        "width": 758,
        "height": 758,
        "alt": "Brimo washed cap, from above"
      },
      {
        "kind": "detail",
        "src": "https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a04-close-960.webp",
        "srcSet": "https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a04-close-480.webp 480w, https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a04-close-960.webp 960w, https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a04-close-1024.webp 1024w",
        "width": 1024,
        "height": 1024,
        "alt": "Brimo washed cap, up close"
      }
    ]
  },
  {
    "id": "a05",
    "slug": "tolva-sunglasses",
    "href": "/pieces/tolva-sunglasses",
    "name": "Tolva sunglasses",
    "price": 39,
    "currency": "EUR",
    "description": "Small oval frames in tortoiseshell acetate.",
    "photo": {
      "src": "https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a05-top-960.webp",
      "srcSet": "https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a05-top-480.webp 480w, https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a05-top-960.webp 960w, https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a05-top-1178.webp 1178w",
      "width": 1178,
      "height": 1178,
      "shadow": "https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a05-shadow.webp",
      "alt": "Tolva sunglasses, from above"
    },
    "place": {"x": 0.5, "y": 0.72, "rotation": -4},
    "gallery": [
      {
        "kind": "detail",
        "src": "https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a05-top-960.webp",
        "srcSet": "https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a05-top-480.webp 480w, https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a05-top-960.webp 960w, https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a05-top-1178.webp 1178w",
        "width": 1178,
        "height": 1178,
        "alt": "Tolva sunglasses, from above"
      },
      {
        "kind": "detail",
        "src": "https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a05-close-960.webp",
        "srcSet": "https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a05-close-480.webp 480w, https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a05-close-960.webp 960w, https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a05-close-1264.webp 1264w",
        "width": 1264,
        "height": 1264,
        "alt": "Tolva sunglasses, up close"
      }
    ]
  },
  {
    "id": "a06",
    "slug": "torvik-chunky-rings",
    "href": "/pieces/torvik-chunky-rings",
    "name": "Torvik chunky rings",
    "price": 29,
    "currency": "EUR",
    "description": "Three plain, heavy rings, polished silver-bright.",
    "photo": {
      "src": "https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a06-top-960.webp",
      "srcSet": "https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a06-top-480.webp 480w, https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a06-top-960.webp 960w, https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a06-top-1142.webp 1142w",
      "width": 1142,
      "height": 1142,
      "shadow": "https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a06-shadow.webp",
      "alt": "Torvik chunky rings, from above"
    },
    "place": {"x": 0.78, "y": 0.76, "rotation": 12},
    "gallery": [
      {
        "kind": "detail",
        "src": "https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a06-top-960.webp",
        "srcSet": "https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a06-top-480.webp 480w, https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a06-top-960.webp 960w, https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a06-top-1142.webp 1142w",
        "width": 1142,
        "height": 1142,
        "alt": "Torvik chunky rings, from above"
      },
      {
        "kind": "detail",
        "src": "https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a06-close-960.webp",
        "srcSet": "https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a06-close-480.webp 480w, https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a06-close-960.webp 960w, https://upfork.dev/assets/e03eab0a0024b154dc8973e588dffb78/hangline/accessories/a06-close-1264.webp 1264w",
        "width": 1264,
        "height": 1264,
        "alt": "Torvik chunky rings, up close"
      }
    ],
    "variants": {
      "label": "Size",
      "options": [{"label": "52", "stock": 3}, {"label": "56", "stock": 4}, {"label": "60", "stock": 2}]
    }
  }
];
18 files224 assets

From the workbench

Written about Hangline — 3D Clothing Store Product Carousel for React, with Sizes, Bag & Accessory Tray

By the developer who built it: how it works, with its real code and live preview in the text, and the lessons learned along the way.

About

A clothing rail for fashion stores, as a React component in CSS 3D. Garments hang on one steel rail in true perspective. The piece in front faces you on a face-out arm, and the rest wait along the rail, edge on, with their own shadows on the wall. Step, drag or flick, and the rail travels: pieces swing a little on their hangers and settle. Choose a colour and a size, and add to the bag, beside the rail or in the piece's own view. An oak tray of accessories sits on the same wall: the room pans across to it.

It is for a small edit, 8 to 20 pieces. It is not a catalogue grid.

Install

Copy registry/hangline/ (15 files) into your project and put your pictures under public/. The component imports its own stylesheet, so your bundler must take CSS imports (Next.js and Vite do). React 19 is the only dependency. There is no CSS framework and no 3D library: the room is DOM and CSS transforms, and the pictures are plain <img> elements.

import Hangline from "./hangline/hangline";

<Hangline
  garments={garments}
  accessories={accessories}
  wall={{ src: "/hangline/room/wall-relief.webp" }}
  tray={{ src: "/hangline/room/tray.webp" }}
  syncUrl
  onAddToBag={addToCart}
  onCheckout={goToCheckout}
/>;

It has been run in a Next.js 16 app (server-rendered, StrictMode) and in a plain Vite app (StrictMode). Give it a box with a height: the whole window, or a section. On a phone it lays itself out as a page, so let it grow there (height: auto on its parents under 700 px, as the demo's registry/ellund/ellund.css does).

The demo store is in registry/demos/ (default is the full store, then a section in a page and a small rail of eight) and registry/ellund/ (its data, page styles and fonts). Read it as an example; it is not part of the component.

Fonts: the component loads none. It reads --hl-display (piece names, default Instrument Serif, then Georgia) and --hl-text (everything else, default the system font). Set them on :root. The demo loads Instrument Serif and Hanken Grotesk.

Names: every class and custom property starts with hl- or --hl-.

What your pictures must be

This is the part that matters. The rail needs a straight-on photograph of each garment on a hanger, cut out, with its hook point, because the component draws one hook for every hanger and hangs the picture from it.

  • A transparent PNG or WebP, the garment facing the camera on its hanger, with the same hanger, light and camera height across the set. Pictures from different shoots look pasted together on one rail.
  • hook: where the hanger's neck meets the drawn hook, 0 to 1 of the picture.
  • size: the piece's height on the rail against a typical jacket (1 is about 70% of the scene's height).
  • shadow.near and shadow.far: the picture's alpha, blurred, for the wall shadows.
  • outline: the garment's silhouette as the points of a CSS polygon(). Only that shape answers the pointer, so a piece waiting beside the front one can be pointed at. It is optional: without it the whole picture answers.

scripts/photos/ is the pipeline that made the demo's set: cut-out (shadows and shaded gaps kept out, each edge cleaned against the backdrop actually beside it), hook point, colourways registered onto one another so a colour change is a clean crossfade, backs colour-matched to their fronts, sizes in WebP and AVIF, the shadow masks and the outline. audit_edges.py scores every cut-out's edge and writes 300% crops of it on each ground it meets. It needs Python 3 with Pillow, NumPy, OpenCV and SciPy. Read it and adapt it to your own pictures: it is a working tool, not a product. PHOTOS.md shows how to run it.

fromShopifyProducts(products, { photo, swatch, gallery }) maps Shopify products to Garment objects. It is a plain mapper and makes no network calls. Be realistic about it: a shop's own product photos are usually not straight-on hanger cut-outs, and on those the rail will not look right until the pictures are redone. You pass it a photo function that returns the prepared hanger picture for a product in a colour.

The demo's pictures are not covered by MIT

The code is MIT. The pictures are not. They keep their own licences or terms, and each one has a row in PHOTOS.md.

  • Every garment and accessory picture is AI-generated, made by us with AI image tools: 58 of the 76 source files name xAI (Grok), and the rest carry an unnamed C2PA mark or nothing (PHOTOS.md lists each file's marks). We have not verified those tools' terms for this use: check them yourself, or replace the pictures. Nothing in this product says they are real photographs.
  • The demo rail has 14 garments (one of them in two colours) and the tray 6 accessories, each with its own pictures: a front on its hanger, the back, a worn view and a close-up, or for an accessory a view from above and a close-up.
  • The wall (plaster) and the tray (oak) are real scans from Poly Haven, CC0.

Replace the pictures with your own before you sell anything. Ellund, its piece names and its prices are invented, and nothing in the demo is for sale.

Props

PropWhat it does
garmentsThe rail. Each has id, slug, href, name, price, currency and colourways (each with a name, a swatch, the hanger photo, its gallery and its sizes with stock); optional compareAtPrice, description, material, care, sizeChart, wearWith
accessoriesThe tray. Each has a photo from above, a place on the tray (x, y, rotation), a gallery, and optional variants. Left out, there is no tray
wall, trayThe wall's relief and the tray's surface: { src }
theme"auto" (default: your dark class, then the system), "light" or "dark"
accentFocus rings, the chosen piece on the tray and the added state's check. Default the stylesheet's own (--hl-accent)
wheel"page" (default): a vertical wheel over the rail scrolls the page. "rail": it moves the rail
looptrue (default): an endless rail. Next after the last piece is the first, a piece that leaves at the front rejoins the rail behind the last one, and the queue is always full. false: the rail stops at its first and last pieces. Needs three pieces or more
openSlug, defaultOpenSlug, onOpenChangeWhich piece is open, controlled or not
syncUrlKeeps the open piece in the address (true for ?piece=, or { param }), with back and deep links
category, onCategoryChangeClothing or accessories, controlled or not
storeName, heading, eyebrowThe top bar's name, and the words beside the rail
detailTopYour site's header height, so an open piece is brought fully into view below it
bag, onBagChangeControl the bag from outside. Left out, it keeps its own
onAddToBagMay return a promise. A rejected one shows that it failed and keeps the choice
onCheckoutThe bag's checkout button
saved, onSavedChangeThe heart on each piece
labels, formatPrice, dirEvery word, every price, and right to left
barExtraYour own control in the top bar (the demo's pull-cord for the light)

Also exported: SizeTiles, SizeGuide, AddToBagPill, BagDrawer, fromShopifyProducts.

Behaviour

  • Moving: the arrows, the arrow keys (Home and End for the first and the last piece), a drag, a flick (at most three pieces), or a click on a waiting piece. Steps chain into one move, and a new command continues from where the rail is, at its speed. The rail is endless: after the last piece comes the first, and the counter runs 14 / 14, 1 / 14. A piece that leaves at the front rejoins the rail behind the last one, out of the far end's depth, so it never appears from nothing.
  • Opening: "See the piece", or Enter on the front piece. The rest of the rail steps aside, and the piece's view opens beside it (a card from the bottom on a phone). Esc, Back, or the browser's back closes it, and focus returns to the piece.
  • Phones: a vertical swipe on the scene scrolls the page and a sideways one moves the rail. The add-to-bag button stays on screen, and every target is at least 44 px.
  • Reduced motion: a step is a short dip through the wall's tone, with no travel and no swing.
  • Without JavaScript: a plain list of the pieces, with their pictures, names, prices and links.
  • Right to left: pass dir="rtl" and your labels; the room mirrors.

Checked, with numbers

On a production build in Chrome, on a notebook with Intel Iris Plus graphics, with all 14 pieces' own pictures, while other work ran on the same machine:

  • Component JavaScript: 21.6 KB gzipped without React; the stylesheet 8.1 KB.
  • First view at 1440 × 900: 853 KB of pictures (the budget is 900). The queue loads small pictures, and a piece takes its full size on its way to the front. The rest of the endless rail follows once the page has loaded on a wide screen (200 KB), and on a phone only when the rail first moves (about 790 KB at 3x, which a visitor who only looks never loads).
  • LCP about 1.0 s on fast 4G, at 1440 and on a phone at full speed.
  • No layout shift. Steps, colours and sizes answer in 24 to 104 ms. No animation frames while idle.

Not met: with the phone's CPU slowed four times, LCP is 3.0 to 3.6 s. One choice of an accessory in three passes had one long frame. The room is laid out in the browser, after hydration.

Checked

Every interaction in both themes, 14 window sizes from 320 to 3440 px, touch, right to left, reduced motion, the keyboard and axe; frame-by-frame filmstrips of the rail, the endless rail across its seam included; no text moving by layout during a move; contrast on the real pixels behind each text; server rendering in StrictMode with deep links; the page without JavaScript; and a plain Vite app. The checks themselves (Playwright scripts) are not part of this package.

Licence

MIT for the code, © UpFork (upfork.dev). The pictures are not covered: see PHOTOS.md and LICENSE.

Reviews and bugs

0 reviews · 0 bugs

Ship it0With fixes0Skip0· 0 reviews

0 bugs0 open0 fixed

Members who have it review it and report its bugs. Sign in

No reviews or bugs yet.

Manual installation

Without the CLI

  1. 01

    Copy the files into your project

    • components/ellund/accessories.ts
    • components/ellund/ellund.css
    • components/ellund/garments.ts
    • components/hangline/buy.tsx
    • components/hangline/detail.tsx
    • components/hangline/hangline.css
    • components/hangline/hangline.tsx
    • components/hangline/hook.tsx
    • components/hangline/icons.tsx
    • components/hangline/labels.ts
    • components/hangline/layout.ts
    • components/hangline/motion.ts
    • components/hangline/rail.ts
    • components/hangline/room.tsx
    • components/hangline/sheets.tsx
    • components/hangline/shopify.ts
    • components/hangline/tray.tsx
    • components/hangline/types.ts

    The paths follow the shadcn/ui layout, with @/ as your project’s import alias.

  2. 02

    Its pictures load from UpFork

    The code above points at UpFork’s copies (18 MB), so there’s nothing to copy. To host them yourself, use Download source: its ZIP has the files where the code expects them, and a README on the switch.

Before you buy

Everything you need to know

How this component gets from the preview into your project, and what buyers ask most.

How to use it

From the preview to your project

  1. 01

    Try it in the preview

    Switch between light and dark, and resize it to phone and tablet widths, before you decide.

  2. 02

    Get it

    Free products are yours with a free account. Paid ones settle in USDT on TRON, sent straight to the wallet on your order.

  3. 03

    Install it

    Components go into your project with one shadcn command, dependencies included. Everything else downloads with a checksum.

  4. 04

    Make it yours

    It's your code now: rename it, restyle it and wire in your real data.

  5. 05

    Or hand it to your AI

    Copy the prompt and let your coding assistant place it in your project, following your conventions.

Building with an AI assistant?

Copy a ready-made prompt with the code, its dependencies and a demo, and your assistant can put it in place for you.

Copy AI prompt

Selling your own work?

Get approved once, then publish components, templates and mobile components, paid in USDT straight to your own wallet.