Skip to content

The react table example doesn't make the <table> element large enough #585

Closed

Description

@KOVIKO

Describe the bug

In the "React Virtual Table Example", the translateY approach to row positioning allows rows to be positioned outside of the <table> element.

This causes issues with at least two things:

  1. A sticky header (<thead style="position:sticky;top:0">) cannot go beyond the bounds of the <table> element
  2. Borders on <tr> elements stop displaying when the <tr> element is outside of the bounds of the <table> element (in Chrome & Firefox)

It's also worth noting that intentionally changing the size of the table causes the rows to become huge, so that doesn't appear to be a solution.

Unless something can be done about the size of the <table> element, it may be best to suggest the padding-rows approach (such as the one used in the "React Table Virtualized Rows Example" in the TanStack Table docs).

Your minimal, reproducible example

https://tanstack.com/virtual/v3/docs/examples/react/table

Steps to reproduce

  1. Go to the "React Virtual Table Example" page in the documentation
  2. Change <thead> to a sticky header (<thead style="position:sticky;top:0">)
  3. Scroll down in the result until the header disappears

Expected behavior

<thead style="position:sticky;top:0"> should remain sticky through the entire table's scrolling.

How often does this bug happen?

Every time

Screenshots or Videos

No response

Platform

  • OS: Windows 11
  • Browser: Vivaldi 6.2.3105.47

tanstack-virtual version

3.0.0-beta.60

TypeScript version

No response

Additional context

No response

Terms & Code of Conduct

  • I agree to follow this project's Code of Conduct
  • I understand that if my bug cannot be reliable reproduced in a debuggable environment, it will probably not be fixed and this issue may even be closed.

Activity

  1. piecyk commented on Sep 12, 2023

    @piecyk
    Collaborator

    @KOVIKO you can't really position: sticky; on <thead> checkout https://css-tricks.com/position-sticky-and-table-headers/

    also for tables better is to avoid the absolute positioning of virtualized items #476

  2. KOVIKO commented on Sep 12, 2023

    @KOVIKO
    Author

    That ticket was very useful for knowing the correct way to do the padding-rows approach! Thank you for that!

    As far as sticky <thead> vs sticky <th> is concerned, they still have the same issue with being restricted to the actual <table> element's bounds.

    If we change the <th> elements in the example to this, we still get the same issue I mentioned:

    <th
      key={header.id}
      colSpan={header.colSpan}
      style={{
        width: header.getSize(),
        position: 'sticky',
        top: 0,
        zIndex: 2,
      }}
    >
    
  3. piecyk commented on Sep 12, 2023

    @piecyk
    Collaborator

    hmm hard to say what is happening, but sticky should work, here virtualization is not adding anything special, like https://codesandbox.io/s/virtual-simple-table-cdqqpg

  4. KOVIKO commented on Sep 12, 2023

    @KOVIKO
    Author

    That example you just provided is using row(s) for padding to keep the <table> element the correct size. However, the example to which I'm referring (https://tanstack.com/virtual/v3/docs/examples/react/table) uses translateY to shift the rows' position in the <table> element, which has the unfortunate side effect of pushing many rows outside of the <table> element's bounds.

    It's in the style attribute of the <tr> elements in the <tbody> element:

    <tr key={row.id} 
    style={{
      height: `${virtualRow.size}px`,
      transform: `translateY(${virtualRow.start - index * virtualRow.size}px)`,
    }}>
    

    To be clear, this isn't necessarily a bug of @tanstack/virtual, but rather a bug of the example used in the documentation.

  5. piecyk commented on Sep 12, 2023

    @piecyk
    Collaborator

    Yep, i agree that table examples are misleading, we should not use the absolution positions here.

  6. vojvodics commented on Oct 30, 2023

    @vojvodics

    @KOVIKO Thanks - your solution worked for me! I'd suggest doing this slightly differently:

    <tr key={row.id} 
    style={{
      height: `${virtualRow.size}px`,
      transform: `translateY(${virtualRows[0]?.start ?? 0}px)`,
    }}>
    

    If the table rows are all fixed height - the calculation for all rows will be the same as the first virtual item.
    If the table row height is dynamic, the calculation won't work, but setting all rows to transform to the start of the first virtual item works.

  7. tboley-vt commented on Nov 12, 2023

    @tboley-vt

    This approach helped me when using scrollMargin:

    <tbody
        css={{
            "&::after": {
                display: "block",
                content: "''",
                // this ensures the table takes up as much size as the total elements by adding padding to the end
                height: `${ virtualizer.getTotalSize() - virtualizer.scrollRect.height}px`,
            },
        }}
    >
        ....
    </tbody>
    
  8. jmalovera10 commented on Dec 7, 2023

    @jmalovera10

    hmm hard to say what is happening, but sticky should work, here virtualization is not adding anything special, like https://codesandbox.io/s/virtual-simple-table-cdqqpg

    This worked out for me! I added the before and after statements around the virtual items map and set the overflowAnchor to none.

  9. tabarra commented on Mar 6, 2024

    @tabarra

    Friendly bump on this issue.
    I've wasted a few days trying to get my tables to work only to find out this was the issue.

  10. piecyk commented on Jul 31, 2025

    @piecyk
    Collaborator

    @tabarra did you try this aproach? #476

  11. rovolution commented on Feb 20, 2026

    @rovolution

    @piecyk thank you for posting this!! absolute life saver

    hmm hard to say what is happening, but sticky should work, here virtualization is not adding anything special, like https://codesandbox.io/s/virtual-simple-table-cdqqpg

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions