scrollTo does not respect pinned Focus offset for carousel

:warning: Before you continue


Before submitting a bug report, please review our troubleshooting documentation at Troubleshoot Issues | Vega Troubleshooting

If you still want to file a bug report, please make sure to fill in all the details below and provide the necessary information.

NOTE: PLEASE ONLY REPORT A SINGLE BUG USING THIS TEMPLATE.
If you’re experiencing multiple issues, please file a separate report for each.


:backhand_index_pointing_right: Bug Description


1. Summary

carousel’s scrollTo only does enough to bring child to view port or make it visible to the user.It does not respect pinnedFocusOffset.

App Name:
App Link on Amazon Appstore (found through Developer Console → Actions column in App List → View on Amazon.com):

Bug Severity
Select one that applies

  • Impacts operation of app
  • Blocks current development
  • Improvement suggestion
  • Issue with documentation (If selected, please share the doc link and describe the issue)
  • Other

2. Steps to Reproduce

  1. just call scrollTo with pinned focus offset set

3. Observed Behavior

Explain what actually happened, noting any discrepancies or malfunctions.

item that we are intending to scrollTo is always alogned at the top.

4. Expected Behavior

Describe what you expected the SDK to do under normal operation.

it should be pinned at pinned focus offset

4.a Possible Root Cause & Temporary Workaround

Fill out anything you have tried. If you don’t know, N/A is acceptable

<!-- Answer here -->

5. Logs or crash report

(Please make sure to provide relevant logs as attachment)

For crash issues, please refer this guide for faster troubleshooting: Detect Where the App Crash Originates | Design and Develop Vega Apps

  • App/Device Logs

  • Crash Logs

  • Crash Report

  • For issues with Vega Studio Extension, please share log files from below folders:
    For v0.22+:

    ~/.vscode/extensions/amazon.vega-extension-<version>/ExtensionLogs
    ~/.vscode/extensions/amazon.vega-ui-extension-<version>/ExtensionLogs
    

    For v0.21 and earlier:

     ~/.vscode/extensions/amazon.kepler-extension-<version>/ExtensionLogs
     ~/.vscode/extensions/amazon.kepler-ui-extension-<version>/ExtensionLogs
    

6. Environment

Please fill out the fields related to your bug below:

  • SDK Version:
    Active SDK Version: 0.22.6150, Vega CLI Version: 1.2.22

  • App State: [Foreground]

  • OS Information: Please ssh into the device via vega exec vda shell (or kepler exec vda shell for v0.21 and earlier) and copy the output from cat /etc/os-release into the answer section below. Note, if you don’t have a simulator running or device attached, the command will respond with vda: no devices/emulators found

    <!-- Answer here if applicable --> 
    

7. Example Code Snippet / Screenshots / Screengrabs

Include any relevant code or component setup in React Native that can help reproduce the bug.

import { Carousel, CarouselRef, type ItemInfo } from '@amazon-devices/kepler-ui-components'
import { useEffect, useRef, useState } from 'react'
import { Dimensions, FocusManager, Pressable, StyleSheet, Text, View, findNodeHandle, type View as ViewType } from 'react-native'

const BASE_HEIGHT = 1080

function scalePixels(size: number): number {
  return Math.round((size * Dimensions.get('window').height) / BASE_HEIGHT)
}

const ITEMS = [
  'random-text-one',
  'random-text-2',
  'random-text-3',
  'random-text-4',
  'random-text-5',
  'random-text-6',
  'random-text-7',
  'random-text-8',
  'random-text-9',
  'random-text-10',
  'random-text-11',
  'random-text-12',
  'random-text-13',
  'random-text-14',
  'random-text-15',
  'random-text-16',
  'random-text-17',
]

const CARD_WIDTH = scalePixels(200)

const CardView = () => null

const itemInfo: ItemInfo[] = [
  {
    view: CardView,
    dimension: { width: CARD_WIDTH, height: CARD_WIDTH },
  },
]

const getItemForIndex = () => CardView

type CardProps = {
  item: string
  index: number
  itemRef: React.RefObject<ViewType>
  focusRequest: number | undefined
}

const Card = ({ item, itemRef, index, focusRequest,  }: CardProps) => {
  const [isFocused, setFocused] = useState(false)

  const styles = useStyles(isFocused)

  useEffect(() => {
    if (focusRequest === index) {
      const handle = findNodeHandle(itemRef.current)
      if (handle) FocusManager.focus(handle)
    }
  }, [focusRequest, index, itemRef])

  return (
    <Pressable
      style={styles.pressable}
      ref={itemRef}
      onFocus={() => setFocused(true)}
      onBlur={() => setFocused(false)}
    >
      <View>
      <Text style={styles.text}>{item}</Text>
      </View>
    </Pressable>
  )
}

export default function SampleCode() {
  const itemRefs = useRef<React.RefObject<ViewType>[]>(
    ITEMS.map(() => ({ current: null })),
  )

  const ref = useRef<CarouselRef<string>>(null)
  useEffect(() => {
    const timer = setTimeout(() => {
      ref.current?.scrollTo(15, true)
    }, 3000)
  })

  return (
    <View style={mainStyles.screen}>
      <Carousel
        ref={ref}
        orientation="vertical"
        data={ITEMS}
        itemDimensions={itemInfo}
        getItemForIndex={getItemForIndex}
        keyProvider={(item) => item}
        numOffsetItems={2}
        maxToRenderPerBatch={6}
        initialStartIndex={0}
        trapFocusOnAxis
        pinnedFocusOffset='50%'
        focusIndicatorType="pinned"
        containerStyle={mainStyles.carousel}
        renderItem={({ item, index }) => (
          <Card
            item={item}
            index={index}
            itemRef={itemRefs.current[index]}
            focusRequest={0}
          />
        )}
      />
    </View>
  )
}

const mainStyles = StyleSheet.create({
  screen: {
    width: '100%',
    height:'100%'
  },
  carousel: {
    width: CARD_WIDTH,
    height: scalePixels(1080),
  }
})

const useStyles = (isFocused: boolean) =>
  StyleSheet.create({
    pressable: {
    backgroundColor: isFocused ? '#008000': '#FF0000',
    width:CARD_WIDTH,
    height:CARD_WIDTH,
  },
    text: {
    color: '#ffffff',
    fontSize: 32,
  },
  })

:backhand_index_pointing_right: Playback Issues


If this is a playback issue, please provide your content URL, any pre-conditions (like geo-location), and let us know if it’s x86 or arm7.


<!-- Describe your playback issue if applicable -->

Please share the following details in addition:_

  • Player SDK: [Bitmovin, Shaka, ...]
  • Player SDK Version: [e.g. 1.23]
    • Audio Codecs: [AAC, ...]
    • Video Codecs: [h.264, mp4]
    • Manifest Types: [m3u8, dash, etc ..]

Q: If applicable, please provide your media/content url
If this is created dynamically, tokenized, etc please provide a way for us to access it

[N/A or Content / Media Url for testing]

Q: Are there any special headers required to reproduce the issue you are facing?

[N/A or Insert Headers]

Additionally please provide the following if possible
Provide Screenshots / Screengrabs / Logs. Please include as much information as you can that will help debug.

<!-- Answer here if applicable --> 

:backhand_index_pointing_right: Additional Context


Any Additional Context you would like to provide?
Add any other relevant information, such as recent updates to the SDK, dependencies, or device OS that may affect the bug.

WHILE, the sample code uses a vertical carousel, same bug is observed for horizontal carousel.

Hi @Rishabh_Ritweek

Thank you for the bug report. A couple of things to note:

  1. You’re using the old Carousel package
    Your import shows:

    import { Carousel, CarouselRef, type ItemInfo } from
    '@amazon-devices/kepler-ui-components'
    

    This is the deprecated VUIC Carousel. The current Carousel is a separate package:
    import { Carousel } from '@amazon-devices/vega-carousel';
    The new @amazon-devices/vega-carousel includes fixes to scrolling behavior and uses updated prop names. We’d recommend migrating first to see if the issue persists. Migration guide here.

  2. Prop name differences in the new package
    If you migrate to @amazon-devices/vega-carousel, the equivalent props are:

  • focusIndicatorType=“pinned” → selectionStrategy=“pinned”
  • pinnedFocusOffset=“50%” → pinnedSelectedItemOffset=“center” (or “50%”)
  • scrollTo(index, animated) → scrollTo(index, animated) (same)
  1. Regarding the scrollTo + pinned offset behavior
    In the new Carousel, scrollTo should position the item at the pinned offset. If it still only brings the item into the viewport edge after migrating, please re-file against @amazon-devices/vega-carousel with your version number, and we can check internally.

Could you try migrating and confirm if the issue reproduces on the new package?

Warm Regards,
Ivy

Thanks @Ivy is this { Carousel } from '@amazon-devices/vega-carousel backward compatible with all previous vega/kepler version?

Hi @Rishabh_Ritweek

The scrollTo + pinned offset behavior is a known limitation. When scrollTo is called, the target item is brought to the anchored viewport position (first item position) rather than where it would be positioned during natural pinned scrolling.
This applies to both the V1 Carousel and the newer @amazon-devices/vega-carousel (V2).

V2 does include additional bug fixes around pinned focus indicator behavior (shipping with v0.23 SDK), but the scrollTo positioning specifically will still differ from natural scroll behavior.

A few questions:

  1. Which app is this for?
  2. Would removing this constraint (making scrollTo respect pinned offset) be a requirement for you, and what priority would this be?
  3. Are you open to working with V2 (@amazon-devices/vega-carousel)? Migration guide here.

Warm Regards,
Ivy

1.scrollTo respecting pinned focus offset is nice to have but we have workarounds for it.Only problem is it goes by remounting whole carousel with a new startIndex(index where we wanna scroll).

2.we can migrate to vega carousel.. I did file the issue few months ago: Carousel wants to bring all non zero indexed child to pinned focus offset . but my example use VUIC carousel.. Am i right to assume that the fix for this would be included in vega carousel as well? ..

3.And, could you please also confirm if you would still want me to file a separate bug in regards to scrollTo and pinned focus offset behaviour for vega carousel? @Ivy

Hello @Rishabh_Ritweek

Following up on the open questions:

  1. Backward compatibility / SDK version support: @amazon-devices/vega-carousel (V2) was released on SDK v0.22. Migration guide here.
    We recommend moving to the latest SDK for the best experience. That said - vega-carousel is an app-bundled component, and its dependencies are already present in earlier OS versions, so you should be able to try it out on SDK 0.21 as well.

  2. Will the pinnedFocusOffset fix be in vega-carousel (V2)? Not currently - scrollTo not respecting pinnedFocusOffset is a known limitation in both V1 and V2. We’ve captured this as a feature request. Migrating to V2 gets you the other pinned focus-indicator fixes, but not the scrollTo positioning behavior specifically.

  3. Should you file a separate bug for V2? No need - we are internally tracking the scrollTo + pinned offset behavior for both V1 and V2.

For now, the startIndex-remount workaround remains the way to position at a pinned offset.

Please let me know here if the backward-compatibility guidance above doesn’t work for you.

Warm regards,
Ivy