Repository: streamlit/streamlit
File: frontend/lib/src/components/elements/Tabs/Tabs.tsx (TypeScript)

Code before:
  // id is only set when the backend registers tabs as a stateful widget
  // (on_change="rerun"). block.id may still be set for CSS key styling.
  const widgetId = node.deltaBlock?.tabContainer?.id
  const isDynamic = Boolean(widgetId)

  // Memoize tab labels to prevent unnecessary effect reruns
  const allTabLabels = useMemo(
    () =>
      node.children.map((child, index) => {
        const tabNode = child as BlockNode
        return tabNode?.deltaBlock?.tab?.label ?? index.toString()
      }),
    [node.children]
  )

  const [activeTabKey, setActiveTabKey] = useState<React.Key>(defaultTabIndex)
  const [activeTabName, setActiveTabName] = useState<string>(() => {
    const tab = node.children[defaultTabIndex] as BlockNode

    return tab?.deltaBlock?.tab?.label ?? "0"
  })

  const tabListRef = useRef<HTMLUListElement>(null)
  const theme = useEmotionTheme()

  const [isOverflowing, setIsOverflowing] = useState(false)
  const [canScrollLeft, setCanScrollLeft] = useState(false)
  const [canScrollRight, setCanScrollRight] = useState(false)

  // Update scroll state based on current scroll position
  const updateScrollState = useCallback((): void => {
    if (tabListRef.current) {
      // eslint-disable-next-line streamlit-custom/no-force-reflow-access -- Required for scroll tracking
      const { scrollLeft, scrollWidth, clientWidth } = tabListRef.current
      const hasOverflow = scrollWidth > clientWidth
      setIsOverflowing(hasOverflow)
      setCanScrollLeft(scrollLeft > 0)
      // Allow small tolerance for floating point rounding
      setCanScrollRight(
        scrollLeft + clientWidth < scrollWidth - SCROLL_TOLERANCE
      )
    }
  }, [])

  // Scroll the tabs by a fixed amount
  const scroll = useCallback((direction: "left" | "right"): void => {
    tabListRef.current?.scrollBy({
      left: direction === "left" ? -SCROLL_AMOUNT : SCROLL_AMOUNT,
      behavior: "smooth",
    })
  }, [])

Review comment (bug):
**suggestion**: I think we can now simplify `isOverflowing = canScrollLeft || canScrollRight` 

Code after:
  // id is only set when the backend registers tabs as a stateful widget
  // (on_change="rerun"). block.id may still be set for CSS key styling.
  const widgetId = node.deltaBlock?.tabContainer?.id
  const isDynamic = Boolean(widgetId)

  // Memoize tab labels to prevent unnecessary effect reruns
  const allTabLabels = useMemo(
    () =>
      node.children.map((child, index) => {
        const tabNode = child as BlockNode
        return tabNode?.deltaBlock?.tab?.label ?? index.toString()
      }),
    [node.children]
  )

  const [activeTabKey, setActiveTabKey] = useState<React.Key>(defaultTabIndex)
  const [activeTabName, setActiveTabName] = useState<string>(() => {
    const tab = node.children[defaultTabIndex] as BlockNode

    return tab?.deltaBlock?.tab?.label ?? "0"
  })

  const tabListRef = useRef<HTMLUListElement>(null)
  const theme = useEmotionTheme()

  const [canScrollLeft, setCanScrollLeft] = useState(false)
  const [canScrollRight, setCanScrollRight] = useState(false)

  // Derive isOverflowing from scroll state instead of tracking separately
  const isOverflowing = canScrollLeft || canScrollRight

  // Update scroll state based on current scroll position
  const updateScrollState = useCallback((): void => {
    if (tabListRef.current) {
      // eslint-disable-next-line streamlit-custom/no-force-reflow-access -- Required for scroll tracking
      const { scrollLeft, scrollWidth, clientWidth } = tabListRef.current
      // Use SCROLL_TOLERANCE for both directions to handle floating point rounding
      setCanScrollLeft(scrollLeft > SCROLL_TOLERANCE)
      setCanScrollRight(
        scrollLeft + clientWidth < scrollWidth - SCROLL_TOLERANCE
      )
    }
  }, [])

  // Scroll the tabs by a fixed amount
  const scroll = useCallback((direction: "left" | "right"): void => {
    tabListRef.current?.scrollBy({
      left: direction === "left" ? -SCROLL_AMOUNT : SCROLL_AMOUNT,
      behavior: "smooth",
    })
  }, [])