Reel
Contained, keyboard-focusable horizontal scrolling for cards and other repeated items.
Default
Scroll through the office desks. Small fixed-width items overflow the preview and scroll freely.
Frodo
Sam
Sméagol
Merry
Pippin
Gandalf
Aragorn
Legolas
Code
<link
rel="component"
href="@threadlabs/looma/components/ui-reel/ui-reel.html"
>
<link
rel="component"
href="@threadlabs/looma/components/ui-card/ui-card.html"
>
<ui-reel
item-width="sm"
aria-label="Fellowship office desks"
>
<div>
<ui-card
padding="sm"
>Frodo</ui-card>
</div>
<div>
<ui-card
padding="sm"
>Sam</ui-card>
</div>
<div>
<ui-card
padding="sm"
>Sméagol</ui-card>
</div>
<div>
<ui-card
padding="sm"
>Merry</ui-card>
</div>
<div>
<ui-card
padding="sm"
>Pippin</ui-card>
</div>
<div>
<ui-card
padding="sm"
>Gandalf</ui-card>
</div>
<div>
<ui-card
padding="sm"
>Aragorn</ui-card>
</div>
<div>
<ui-card
padding="sm"
>Legolas</ui-card>
</div>
</ui-reel><script setup>
import { UiCard, UiReel } from "@threadlabs/looma";
</script>
<template>
<UiReel
item-width="sm"
aria-label="Fellowship office desks"
>
<div>
<UiCard
padding="sm"
>Frodo</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Sam</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Sméagol</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Merry</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Pippin</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Gandalf</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Aragorn</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Legolas</UiCard>
</div>
</UiReel>
</template>import { UiCard, UiReel } from "@threadlabs/looma";
export default function Example() {
return <UiReel
itemWidth="sm"
aria-label="Fellowship office desks"
>
<div>
<UiCard
padding="sm"
>Frodo</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Sam</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Sméagol</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Merry</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Pippin</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Gandalf</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Aragorn</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Legolas</UiCard>
</div>
</UiReel>;
}/** @jsxImportSource preact */
import { UiCard, UiReel } from "@threadlabs/looma";
export default function Example() {
return <UiReel
itemWidth="sm"
aria-label="Fellowship office desks"
>
<div>
<UiCard
padding="sm"
>Frodo</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Sam</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Sméagol</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Merry</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Pippin</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Gandalf</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Aragorn</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Legolas</UiCard>
</div>
</UiReel>;
}<script>
import { UiCard, UiReel } from "@threadlabs/looma";
</script>
<UiReel
itemWidth="sm"
aria-label="Fellowship office desks"
>
<div>
<UiCard
padding="sm"
>Frodo</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Sam</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Sméagol</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Merry</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Pippin</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Gandalf</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Aragorn</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Legolas</UiCard>
</div>
</UiReel>import { Component } from "@angular/core";
import { UiCard, UiReel } from "@threadlabs/looma";
@Component({
selector: "example-view",
standalone: true,
imports: [UiReel, UiCard],
template: `
<div
ui-reel
[itemWidth]="'sm'"
aria-label="Fellowship office desks"
>
<div>
<ng-template
ui-card
[padding]="'sm'"
>Frodo</ng-template>
</div>
<div>
<ng-template
ui-card
[padding]="'sm'"
>Sam</ng-template>
</div>
<div>
<ng-template
ui-card
[padding]="'sm'"
>Sméagol</ng-template>
</div>
<div>
<ng-template
ui-card
[padding]="'sm'"
>Merry</ng-template>
</div>
<div>
<ng-template
ui-card
[padding]="'sm'"
>Pippin</ng-template>
</div>
<div>
<ng-template
ui-card
[padding]="'sm'"
>Gandalf</ng-template>
</div>
<div>
<ng-template
ui-card
[padding]="'sm'"
>Aragorn</ng-template>
</div>
<div>
<ng-template
ui-card
[padding]="'sm'"
>Legolas</ng-template>
</div>
</div>
`,
})
export default class Example {}Gap, item width, and snap
Scroll the office desks sideways: medium-width items snap to the center when you release.
Frodo
Sam
Sméagol
Merry
Pippin
Gandalf
Aragorn
Legolas
Code
<link
rel="component"
href="@threadlabs/looma/components/ui-reel/ui-reel.html"
>
<link
rel="component"
href="@threadlabs/looma/components/ui-card/ui-card.html"
>
<ui-reel
gap="m"
item-width="md"
snap="center"
aria-label="Fellowship office desks"
>
<div>
<ui-card
padding="sm"
>Frodo</ui-card>
</div>
<div>
<ui-card
padding="sm"
>Sam</ui-card>
</div>
<div>
<ui-card
padding="sm"
>Sméagol</ui-card>
</div>
<div>
<ui-card
padding="sm"
>Merry</ui-card>
</div>
<div>
<ui-card
padding="sm"
>Pippin</ui-card>
</div>
<div>
<ui-card
padding="sm"
>Gandalf</ui-card>
</div>
<div>
<ui-card
padding="sm"
>Aragorn</ui-card>
</div>
<div>
<ui-card
padding="sm"
>Legolas</ui-card>
</div>
</ui-reel><script setup>
import { UiCard, UiReel } from "@threadlabs/looma";
</script>
<template>
<UiReel
gap="m"
item-width="md"
snap="center"
aria-label="Fellowship office desks"
>
<div>
<UiCard
padding="sm"
>Frodo</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Sam</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Sméagol</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Merry</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Pippin</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Gandalf</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Aragorn</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Legolas</UiCard>
</div>
</UiReel>
</template>import { UiCard, UiReel } from "@threadlabs/looma";
export default function Example() {
return <UiReel
gap="m"
itemWidth="md"
snap="center"
aria-label="Fellowship office desks"
>
<div>
<UiCard
padding="sm"
>Frodo</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Sam</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Sméagol</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Merry</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Pippin</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Gandalf</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Aragorn</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Legolas</UiCard>
</div>
</UiReel>;
}/** @jsxImportSource preact */
import { UiCard, UiReel } from "@threadlabs/looma";
export default function Example() {
return <UiReel
gap="m"
itemWidth="md"
snap="center"
aria-label="Fellowship office desks"
>
<div>
<UiCard
padding="sm"
>Frodo</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Sam</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Sméagol</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Merry</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Pippin</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Gandalf</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Aragorn</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Legolas</UiCard>
</div>
</UiReel>;
}<script>
import { UiCard, UiReel } from "@threadlabs/looma";
</script>
<UiReel
gap="m"
itemWidth="md"
snap="center"
aria-label="Fellowship office desks"
>
<div>
<UiCard
padding="sm"
>Frodo</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Sam</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Sméagol</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Merry</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Pippin</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Gandalf</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Aragorn</UiCard>
</div>
<div>
<UiCard
padding="sm"
>Legolas</UiCard>
</div>
</UiReel>import { Component } from "@angular/core";
import { UiCard, UiReel } from "@threadlabs/looma";
@Component({
selector: "example-view",
standalone: true,
imports: [UiReel, UiCard],
template: `
<div
ui-reel
[gap]="'m'"
[itemWidth]="'md'"
[snap]="'center'"
aria-label="Fellowship office desks"
>
<div>
<ng-template
ui-card
[padding]="'sm'"
>Frodo</ng-template>
</div>
<div>
<ng-template
ui-card
[padding]="'sm'"
>Sam</ng-template>
</div>
<div>
<ng-template
ui-card
[padding]="'sm'"
>Sméagol</ng-template>
</div>
<div>
<ng-template
ui-card
[padding]="'sm'"
>Merry</ng-template>
</div>
<div>
<ng-template
ui-card
[padding]="'sm'"
>Pippin</ng-template>
</div>
<div>
<ng-template
ui-card
[padding]="'sm'"
>Gandalf</ng-template>
</div>
<div>
<ng-template
ui-card
[padding]="'sm'"
>Aragorn</ng-template>
</div>
<div>
<ng-template
ui-card
[padding]="'sm'"
>Legolas</ng-template>
</div>
</div>
`,
})
export default class Example {}API
Package: @threadlabs/looma · Native root: div
Attributes
| Name | Description | Property | Type | Default | Allowed values |
|---|---|---|---|---|---|
gap | Space between items, on the spacing scale: xs is 0.5rem, s 0.75rem, m 1rem (also the default), l 1.5rem, and xl 2rem. The --ui-reel-gap custom property, set on :root, an ancestor, or the component itself, overrides it. | gap | keyword | — | xs, s, m, l, xl |
item-width | A fixed width for every item: sm is 12rem, md is 16rem, and lg is 20rem. Unset, each item keeps its content's width. Items never shrink to fit, so the reel scrolls sideways once they overflow. | itemWidth | keyword | — | sm, md, lg |
snap | Snaps scrolling to items: start comes to rest with an item's start edge at the reel's start, and center with an item centred in the reel. Unset, the reel scrolls freely. Wrap a component item in a plain element when snapping: the wrapper receives snap alignment while the component keeps ownership of its root styles. | snap | keyword | — | start, center |
Framework props
| Name | Type | Default | Allowed values |
|---|---|---|---|
gap | "xs" | "s" | "m" | "l" | "xl" | — | xs, s, m, l, xl |
itemWidth | "sm" | "md" | "lg" | — | sm, md, lg |
snap | "start" | "center" | — | start, center |
Events
No events.
Slots
| Name | Purpose |
|---|---|
default | Default child content. |
Design tokens
Set shared theme properties on a theme boundary. Component hooks apply only to their owning component.
Component tokens
| Token | Declared values | Fallback |
|---|---|---|
--ui-reel-gap | var(--ui-space-4) | var(--ui-space-2) | var(--ui-space-3) | var(--ui-space-5) | var(--ui-space-6) | — |
--ui-reel-item-width | max-content | 12rem | 16rem | 20rem | — |
Shared tokens
| Token | Fallback |
|---|---|
--ui-scroll-fade-size | 24px |
--ui-space-2 | — |
--ui-space-3 | — |
--ui-space-4 | — |
--ui-space-5 | — |
--ui-space-6 | — |