Amazon Developer

as

Settings
Sign out
Notifications
Alexa
Amazon Appstore
Ring
AWS
Documentation
Support
Contact Us
My Cases
Get Started
Design and Develop
Publish
Reference
Support

Step 5: Carousel Migration

This step is required only for apps that use the Carousel component. If your app doesn't use Carousel, skip to Step 6: Testing Updates.

With RN 0.83, the Carousel component moved from the kepler-ui-components package to a separate package in @amazon-devices. If you use Carousel, you need to migrate the component to the new package.

grep -rn "import.*Carousel.*from.*kepler-ui-components" src/ --include="*.tsx" --include="*.ts" --include="*.jsx" --include="*.js"

If no results, proceed to Step 6: Testing Updates.

5.2 Update dependencies

{
  "dependencies": {
    "@amazon-devices/vega-carousel": "~1.0.0"
  }
}
  • If Carousel is the only import from kepler-ui-components, replace the dependency entirely.
  • If other components are also imported, keep kepler-ui-components and add vega-carousel alongside it.

5.3 Update import statements

// ❌ BEFORE
import { Carousel } from '@amazon-devices/kepler-ui-components';

// ✅ AFTER
import { Carousel, CarouselRenderInfo } from '@amazon-devices/vega-carousel';

5.4 Migrate data access pattern

Carousel V2 replaces the simple data array prop with a dataAdapter pattern for better performance.

// ❌ BEFORE (V1) — simple data array
<Carousel
  data={items}
  keyProvider={(item, index) => `item-${item.id}`}
  renderItem={({ item, index }) => <ItemCard item={item} />}
/>

// ✅ AFTER (V2) — dataAdapter pattern
const getItem = useCallback((index: number) => {
  if (index >= 0 && index < items.length) {
    return items[index];
  }
  return undefined;
}, [items]);

const getItemCount = useCallback(() => {
  return items.length;
}, [items]);

const getItemKey = useCallback((info: CarouselRenderInfo) => {
  return `item-${info.item.id}`;
}, []);

const notifyDataError = useCallback((error: CarouselDataError) => {
  return false;
}, []);

<Carousel
  dataAdapter={{
    getItem,
    getItemCount,
    getItemKey,
    notifyDataError,
  }}
  renderItem={({ item, index }) => <ItemCard item={item} />}
/>

5.5 Migrate props

Update prop names to the V2 Prop name in the table below.

V1 Prop V2 Prop Notes
data dataAdapter See Step 5.4
keyProvider dataAdapter.getItemKey Now takes CarouselRenderInfo instead of (item, index)
rowId (number) uniqueId (string) Convert number to string
maxToRenderPerBatch renderedItemsCount Same functionality, new name
hasTVPreferredFocus hasPreferredFocus Now works on any device
trapFocusOnAxis trapSelectionOnOrientation Same functionality, new name
itemPadding itemStyle.itemPadding Moved into itemStyle object
itemSelectionExpansion itemStyle.selectedItemScaleFactor Single uniform scale factor. V1 used separate widthScale and heightScale values, but V2 uses a single uniform scale factor. If your V1 implementation had different width/height scales, use heightScale as the starting point and visually test the result.
itemScrollDelay animationDuration.itemScrollDuration Moved into animationDuration object
focusIndicatorType selectionStrategy Value mapping: fixedanchored, naturalnatural, pinnedpinned
pinnedFocusOffset pinnedSelectedItemOffset Also accepts "start", "center", "end"
selectionBorderStrategy selectionBorder.borderStrategy Moved into selectionBorder object

Remove these deprecated V1 props (no V2 equivalent)

  • itemDimensions
  • getItemForIndex
  • firstItemOffset
  • selectionBorder.enabled

5.6 Migrate event handlers

If you used onFocus or onFocusUpdate for tracking the selected carousel item, migrate to onSelectionChanged.

// ❌ BEFORE (V1) — using onFocus to track selection
const [selectedIndex, setSelectedIndex] = useState(0);

<Carousel
  onFocus={(index) => setSelectedIndex(index)}
/>

// ✅ AFTER (V2) — using onSelectionChanged
const onSelectionChanged = useCallback((event: CarouselSelectionChangeEvent) => {
  const item = items[event.index];
  // Your logic here
}, [items]);

<Carousel
  onSelectionChanged={onSelectionChanged}
/>

5.7 Complete migration example

// ✅ Complete V2 Carousel implementation
import React, { useCallback } from 'react';
import { Carousel, CarouselRenderInfo, CarouselSelectionChangeEvent } from '@amazon-devices/vega-carousel';

interface MovieItem {
  id: string;
  title: string;
  thumbnail: string;
}

function MovieCarousel({ movies }: { movies: MovieItem[] }) {
  const getItem = useCallback((index: number) => {
    return index >= 0 && index < movies.length ? movies[index] : undefined;
  }, [movies]);

  const getItemCount = useCallback(() => movies.length, [movies]);

  const getItemKey = useCallback((info: CarouselRenderInfo) => {
    return `movie-${info.item.id}`;
  }, []);

  const notifyDataError = useCallback(() => false, []);

  const onSelectionChanged = useCallback((event: CarouselSelectionChangeEvent) => {
    console.log('Selected movie:', movies[event.index]?.title);
  }, [movies]);

  return (
    <Carousel
      dataAdapter={{ getItem, getItemCount, getItemKey, notifyDataError }}
      renderItem={({ item }) => <MovieCard movie={item} />}
      uniqueId="movie-carousel"
      renderedItemsCount={7}
      hasPreferredFocus={true}
      selectionStrategy="anchored"
      onSelectionChanged={onSelectionChanged}
      itemStyle={{
        itemPadding: 16,
        selectedItemScaleFactor: 1.1,
      }}
      animationDuration={{
        itemScrollDuration: 0.3,
      }}
    />
  );
}

For the complete property mapping reference, see the Vega Carousel documentation.


Last updated: Jul 09, 2026