MDC

Carousel

READMEDemo

A horizontal, scroll-snap carousel container that lays out its mdc-carousel-item children in large / medium / small widths.

The carousel is not part of @material/web; it mirrors the Jetpack Compose Material 3 carousel (HorizontalMultiBrowseCarousel / HorizontalUncontainedCarousel). For a horizontal carousel the three item sizes differ only in width and corner roundness — every cell shares one height and one interaction model.

Elements

Element Role
mdc-carousel The container — owns layout, scroll-snap, focus
mdc-carousel-item A sized cell; declares size, tracks active

Usage

<mdc-carousel>
    <mdc-carousel-item size="large">…</mdc-carousel-item>
    <mdc-carousel-item size="medium">…</mdc-carousel-item>
    <mdc-carousel-item size="small">…</mdc-carousel-item>
    <mdc-carousel-item size="large">…</mdc-carousel-item>
</mdc-carousel>

Sizing

Item widths derive from preferred-item-width (default 186px):

Size Width Corner roundness
large min(preferred-item-width, container width) 28px
medium (large + small) / 2 20px
small clamp(large / 3, 40px, 56px) 12px

Every value is overridable through the --mdc-carousel-* CSS custom properties below. Widths are recomputed when the container resizes.

Variants

  • multi-browse (default) — the row mixes large / medium / small items. Items snap to the leading keyline and the row clips at the container edge.
  • uncontained — all items share one width and the row scrolls freely (no snap), with the trailing item peeking at the edge.

Properties

mdc-carousel

Property Attribute Type Default
variant variant 'multi-browse' | 'uncontained' 'multi-browse'
preferredItemWidth preferred-item-width number 186
activeIndex (read only) number -1

mdc-carousel-item

Property Attribute Type Default
size size 'large' | 'medium' | 'small' 'medium'
active active boolean false
index index number 0

Events

Event Detail Description
carousel-active-change { item, index } Fired when the focal (leading) item changes.

Methods

  • scrollToItem(index) — scrolls the item at index to the leading keyline (smooth). Also driven by ← / → / Home / End when the carousel is focused (tabindex="0").

CSS custom properties

Property Default
--mdc-carousel-small-item-width computed
--mdc-carousel-medium-item-width computed
--mdc-carousel-large-item-width computed
--mdc-carousel-*-item-shape-start-start 28px / 20px / 12px
--mdc-carousel-*-item-shape-start-end 28px / 20px / 12px
--mdc-carousel-*-item-shape-end-start 28px / 20px / 12px
--mdc-carousel-*-item-shape-end-end 28px / 20px / 12px
--mdc-carousel-item-spacing 8px
--mdc-carousel-item-height auto (stretched to tallest)
--mdc-carousel-container-padding-block-start 8px
--mdc-carousel-container-padding-block-end 8px
--mdc-carousel-container-padding-inline-start 16px
--mdc-carousel-container-padding-inline-end 16px

* in the shape rows stands for small / medium / large (the item size); the per-size defaults are the extra-large (28px), large-increased (20px) and medium (12px) MD3 corners respectively.

Size

Code
<style>
    .cds-card {
        display: flex;
        align-items: center;
        justify-content: center;
        box-sizing: border-box;
        height: 180px;
        padding: 8px;
        font: 500 14px/20px Roboto, system-ui, sans-serif;
        color: var(--md-sys-color-on-surface, #1d1b20);
    }
    .cds-a { background: var(--md-sys-color-surface-container-high, #e6e0e9); }
    .cds-b { background: var(--md-sys-color-secondary-container, #e8def8); }
    .cds-c { background: var(--md-sys-color-tertiary-container, #ffd8e4); }
</style>

<!-- The three sizes differ only in width and corner roundness; height is shared -->
<mdc-carousel aria-label="Carousel item sizes">
    <mdc-carousel-item size="large"><div class="cds-card cds-a">Large</div></mdc-carousel-item>
    <mdc-carousel-item size="medium"><div class="cds-card cds-b">Medium</div></mdc-carousel-item>
    <mdc-carousel-item size="small"><div class="cds-card cds-c">Small</div></mdc-carousel-item>
    <mdc-carousel-item size="medium"><div class="cds-card cds-c">Medium</div></mdc-carousel-item>
    <mdc-carousel-item size="small"><div class="cds-card cds-a">Small</div></mdc-carousel-item>
    <mdc-carousel-item size="large"><div class="cds-card cds-b">Large</div></mdc-carousel-item>
    <mdc-carousel-item size="medium"><div class="cds-card cds-a">Medium</div></mdc-carousel-item>
    <mdc-carousel-item size="small"><div class="cds-card cds-b">Small</div></mdc-carousel-item>
</mdc-carousel>

Preferred Item Width

Code
<style>
    .cdp-card {
        display: flex;
        align-items: center;
        justify-content: center;
        box-sizing: border-box;
        height: 180px;
        padding: 8px;
        font: 500 14px/20px Roboto, system-ui, sans-serif;
        color: var(--md-sys-color-on-surface, #1d1b20);
    }
    .cdp-a { background: var(--md-sys-color-surface-container-high, #e6e0e9); }
    .cdp-b { background: var(--md-sys-color-secondary-container, #e8def8); }
    .cdp-c { background: var(--md-sys-color-tertiary-container, #ffd8e4); }
</style>

<!-- preferred-item-width tunes the large item; small ≈ ⅓ of large (40–56px), medium the average -->
<mdc-carousel preferred-item-width="120" aria-label="120px preferred width">
    <mdc-carousel-item size="large"><div class="cdp-card cdp-a">Large</div></mdc-carousel-item>
    <mdc-carousel-item size="medium"><div class="cdp-card cdp-b">Medium</div></mdc-carousel-item>
    <mdc-carousel-item size="small"><div class="cdp-card cdp-c">Small</div></mdc-carousel-item>
    <mdc-carousel-item size="large"><div class="cdp-card cdp-c">Large</div></mdc-carousel-item>
    <mdc-carousel-item size="medium"><div class="cdp-card cdp-a">Medium</div></mdc-carousel-item>
    <mdc-carousel-item size="small"><div class="cdp-card cdp-b">Small</div></mdc-carousel-item>
</mdc-carousel>

<!-- default preferred-item-width (186) -->
<mdc-carousel aria-label="Default 186px preferred width">
    <mdc-carousel-item size="large"><div class="cdp-card cdp-a">Large</div></mdc-carousel-item>
    <mdc-carousel-item size="medium"><div class="cdp-card cdp-b">Medium</div></mdc-carousel-item>
    <mdc-carousel-item size="small"><div class="cdp-card cdp-c">Small</div></mdc-carousel-item>
    <mdc-carousel-item size="large"><div class="cdp-card cdp-c">Large</div></mdc-carousel-item>
    <mdc-carousel-item size="medium"><div class="cdp-card cdp-a">Medium</div></mdc-carousel-item>
    <mdc-carousel-item size="small"><div class="cdp-card cdp-b">Small</div></mdc-carousel-item>
</mdc-carousel>

<!-- larger preferred width → bigger large item, wider small/medium -->
<mdc-carousel preferred-item-width="260" aria-label="260px preferred width">
    <mdc-carousel-item size="large"><div class="cdp-card cdp-a">Large</div></mdc-carousel-item>
    <mdc-carousel-item size="medium"><div class="cdp-card cdp-b">Medium</div></mdc-carousel-item>
    <mdc-carousel-item size="small"><div class="cdp-card cdp-c">Small</div></mdc-carousel-item>
    <mdc-carousel-item size="large"><div class="cdp-card cdp-c">Large</div></mdc-carousel-item>
    <mdc-carousel-item size="medium"><div class="cdp-card cdp-a">Medium</div></mdc-carousel-item>
    <mdc-carousel-item size="small"><div class="cdp-card cdp-b">Small</div></mdc-carousel-item>
</mdc-carousel>

Variant

Code
<style>
    .cd-card {
        display: flex;
        align-items: center;
        justify-content: center;
        box-sizing: border-box;
        height: 180px;
        padding: 8px;
        font: 500 14px/20px Roboto, system-ui, sans-serif;
        color: var(--md-sys-color-on-surface, #1d1b20);
    }
    .cd-a { background: var(--md-sys-color-surface-container-high, #e6e0e9); }
    .cd-b { background: var(--md-sys-color-secondary-container, #e8def8); }
    .cd-c { background: var(--md-sys-color-tertiary-container, #ffd8e4); }
</style>

<!-- multi-browse (default): mixes large / medium / small items that snap to the leading keyline -->
<mdc-carousel aria-label="Multi-browse carousel">
    <mdc-carousel-item size="large"><div class="cd-card cd-a">Large</div></mdc-carousel-item>
    <mdc-carousel-item size="medium"><div class="cd-card cd-b">Medium</div></mdc-carousel-item>
    <mdc-carousel-item size="small"><div class="cd-card cd-c">Small</div></mdc-carousel-item>
    <mdc-carousel-item size="large"><div class="cd-card cd-c">Large</div></mdc-carousel-item>
    <mdc-carousel-item size="medium"><div class="cd-card cd-a">Medium</div></mdc-carousel-item>
    <mdc-carousel-item size="small"><div class="cd-card cd-b">Small</div></mdc-carousel-item>
    <mdc-carousel-item size="large"><div class="cd-card cd-b">Large</div></mdc-carousel-item>
    <mdc-carousel-item size="medium"><div class="cd-card cd-c">Medium</div></mdc-carousel-item>
</mdc-carousel>

<!-- uncontained: uniform width, scrolls freely (no snap), trailing item peeks at the edge -->
<mdc-carousel variant="uncontained" aria-label="Uncontained carousel">
    <mdc-carousel-item size="large"><div class="cd-card cd-a">One</div></mdc-carousel-item>
    <mdc-carousel-item size="large"><div class="cd-card cd-b">Two</div></mdc-carousel-item>
    <mdc-carousel-item size="large"><div class="cd-card cd-c">Three</div></mdc-carousel-item>
    <mdc-carousel-item size="large"><div class="cd-card cd-a">Four</div></mdc-carousel-item>
    <mdc-carousel-item size="large"><div class="cd-card cd-b">Five</div></mdc-carousel-item>
    <mdc-carousel-item size="large"><div class="cd-card cd-c">Six</div></mdc-carousel-item>
</mdc-carousel>