Giter VIP home page Giter VIP logo

react-virtuoso's Introduction

npm version

React Virtuoso - the most complete React virtualization rendering list/table/grid family of components.

For live examples and documentation, check the documentation website.

Sponsors

If you are using Virtuoso for work, sponsor it. Any donation helps a lot with the project development and maintenance.

Get Started

npm install react-virtuoso
import * as React from 'react'
import * as ReactDOM from 'react-dom'
import { Virtuoso } from 'react-virtuoso'

const App = () => {
  return <Virtuoso style={{ height: '400px' }} totalCount={200} itemContent={index => <div>Item {index}</div>} />
}

ReactDOM.render(<App />, document.getElementById('root'))

The Virtuoso message list component is built specifically for human/chatbot conversations. In addition to the virtualized rendering, the component exposes an imperative data management API that gives you the necessary control over the scroll position when older messages are loaded, new messages arrive, and when the user submits a message. The scroll position can update instantly or with a smooth scroll animation.

The GroupedVirtuoso component is a variant of the "flat" Virtuoso, with the following differences:

  • Instead of totalCount, the component exposes groupCounts: number[] property, which specifies the amount of items in each group. For example, passing [20, 30] will render two groups with 20 and 30 items each;
  • In addition the itemContent property, the component requires an additional groupContent property, which renders the group header. The groupContent callback receives the zero-based group index as a parameter.

The VirtuosoGrid component displays same sized items in multiple columns. The layout and item sizing is controlled through CSS class properties, which allows you to use media queries, min-width, percentage, etc.

The TableVirtuoso component works just like Virtuoso, but with HTML tables. It supports window scrolling, sticky headers, sticky columns, and works with React Table and MUI Table.

Works With Your UI Library of Choice

You can customize the markup up to your requirements - check the Material UI list demo. If you need to support reordering, check the React Sortable HOC example.

Documentation and Demos

For in-depth documentation and live examples of the supported features and live demos, check the documentation website.

Browser support

To support legacy browsers, you might have to load a ResizeObserver Polyfill before using react-virtuoso:

import ResizeObserver from 'resize-observer-polyfill'
if (!window.ResizeObserver)
  window.ResizeObserver = ResizeObserver

Author

Petyo Ivanov @petyosi.

Contributing

Fixes and new Features

To run the tests, use npm run test. An end-to-end browser-based test suite is runnable with npm run e2e, with the pages being e2e/*.tsx and the tests e2e/*.test.ts.

A convenient way to debug something is to preview the test cases in the browser. To do that, run npm run dev - it will launch a Ladle server that lets you browse the components in the examples folder.

License

MIT License.

react-virtuoso's People

Contributors

alexgleason avatar astrotars avatar bigtomm avatar cryptoethic avatar cvanem avatar dependabot[bot] avatar henrinormak avatar hoop71 avatar iamstarkov avatar imohammadreza avatar mihkeleidast avatar mocantimoteidavid avatar mrv1k avatar nonoroazoro avatar oliviertassinari avatar petyosi avatar ppiyush13 avatar ru-van-urk avatar sanderkranz avatar sathusank avatar seahorsepip avatar sei666 avatar spiderhands avatar stephenh avatar subev avatar theamanjs avatar thiagoissao avatar ts1994tw avatar vnesterovspirent avatar zakuru avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

react-virtuoso's Issues

Use with react-custom-scrollbars

Could this library be used alongside react-custom-scrollbars? I was previously using react-window and this was supported by passing a ref of the rendered list to react-custom-scrollbars onScroll method but doing the same seems to not work with virtuoso as the ref is not a DOM element.

I've attached an example of what I'm trying to achieve.
Edit: here's the link - https://codesandbox.io/s/practical-bouman-z6wqd

Specifying a different itemHeight per item/group?

We have a GroupedVirtuoso list with known item heights. But each item and group header has a different height.

Is it possible to achieve this using the itemHeight prop ? Like passing a function instead of a number, function that would take a group index or an item index and would return an itemHeight.

something like

<GroupedVirtuoso
itemHeight={(itemIndex) => number}
groupHeight={(groupIndex) => number}
/>

BTW. I cannot use the auto sizer feature, because most of my items have negative margins for imbrication/overlapping.

Thx

Create callback prop for getting total height

I need get full height for implement my own scroll behavior around scrollTop for VirtuosoScroller.
I think that need/can to be implemented some callback prop for Virtuoso, that can be passed into VirtuosoView and call function with fillerHeight as param.
if you know some better solution. pls tell me
if this idea not bad - i can try to create PR
sorry for my lang

Feature request: horizontal list

I'm hacking at the library to get it to display a horizontal list. It seems built only for vertical lists.

Is there any easy way to get it to display the virtualized list horizontally instead of vertically?

Table support

I am currently trying to find a way to use one of your components to render table rows (specifically using material ui).

Here is the general idea of what I'm aiming for

<Table>
    <TableHead>...</TableHead>
    <TableBody>
        <Virtuoso ... />
    </TableBody>
</Table>

however I see the issue is that your Virtuoso component renders a few divs I'm assuming to track height, number of items in view, etc.

Maybe there is a way we can pass our own component as a prop to render as a parent element? something={TableBody}?

I'm essentially asking if there is a good way to prevent this kind of markup below?

...
<tbody>
    <div ...>
        <div ...>
            <tr>
...

Let me know what else I can provide. I appreciate what you have done so far!

Empty list on display changes

When the parent element of Virtuoso changes its display mode from visible to hidden, the list is eventually empty.

I use @reach/tabs and all the TabPanel elements contain a Virtuoso list. If I repeatedly click on the tabs to hide and display my lists, one of them end to be empty.

I also tested by manually set/unset display: none on the parent and the result is the same.

Any idea?

Thanks for the great work by the way πŸ‘

Demo flickers on page scroll

Hey, just stumbled on your library (via Sid mailing list). Looks slick πŸ™Œ

I spotted on the demo site it seems to not like the browser page scrolling? It results in a nasty flicker and a times no longer paints the list.

https://vimeo.com/339051112

Device is an iPhone X, iOS 12.2. Suspect you could replicate on other iOS devices.

Cannot scroll very large lists all the way down when item styling affects height

I was just playing with the Virtuoso component, and noticed for lists with very large number of items, you can't scroll all the way down if list items have styling that affects their height. You can verify this with a list of 1,000,000 items with some vertical padding or a larger font size set on the items. Not a deal breaker as it's unlikely this happens in practice, but was wondering what the underlying issue is.

Support for sticky items

Marking certain indices as sticky can be used to create groups. The rendering itself won't change, but the implementation should switch the pinned items to the closest sticky one.

List not showing enough elements when big differences in height

This is a bit of a special and maybe even contrived case, at least to the extent I did it, but this could lead to mistakes in more reasonable examples aswell.

Virtuoso doesn't really handle big differences in height very well, when there is a sudden decrease in size.

<Virtuoso style={{ width: '100%', height: '400px' }} overscan={400} totalCount={200} item={(index: number) => {
            return <div style={{height: (index < 100 ? 200 : 20)}}>test {index}</div>;
        }} />

Since the first 100 items have a height of 200 Virtuoso assumes that height for all elements to begin with and once you scroll down to the items with a height of 20 it does not render enough items to fill the viewport.

I'm not sure if I'm doing something wrong or this is simply a limitation of the list.

Support grid layout?

Hi, I was wondering if you do plan to support a grid layout? I think a simple fixed column width grid support would be more than enough to cover most of the use cases.

Using ItemContainer and useState causes rerender

I'm using a GroupedVirtuoso with buttons in each row. To make my list more accessible, I'm trying to keep track of the focused index, so I can auto-scroll the list as a user tabs through it.

However, In order to properly style my list elements, I needed to add an ItemContainer. Once I add the ItemContainer in combination with setFocusedIndex via useState, it will always cause a rerender of the list once I try to tab past the first button and thus can't tab anywhere past the first row.

CodeSandbox with reproduced the issue:
https://codesandbox.io/s/heuristic-dijkstra-ml1sj

Item prop does accepts only ReactElement as a return type.

type ReactNode = ReactChild | ReactFragment | ReactPortal | boolean | null | undefined;

All of the above types function correctly to render a React component. But item as a prop lacks the alternatives to ReactElement in it's return type.

I tried to return null from item and it works on the javascript side. But I have to cast null as ReactElement to make it work in ts.

Would you consider to type item as (index: number) => ReactNode? Or is there a reason why the return type is strict to be ReactElement only?

Breaks when items are removed (totalCount changed)

When totalCount is lowered (e.g. to 1), no items are rendered. Changing the totalCount appears to break the component in other circumstances too. For example, if totalCount is lowered to 0 and then increased again, only the last item is rendered.

Expose active group index

I'm building something similar to https://virtuoso.dev/scroll-to-group/

I'd like to trigger some functionality whenever a new group index becomes active to do things like add an active class to the navigational buttons, but I can't seem to find anything that exposes the current active group index.

Am I missing something? Otherwise, I think it would be best to expose it in the scrollingStateChange or in itemsRendered

webpack: Failed to compile

ERROR in ./node_modules/react-virtuoso/dist/react-virtuoso.es.production.js
Module parse failed: /Users/xx/Desktop/xx/react-virtuoso/dist/react-virtuoso.es.production.js Unexpected token (1:12692)
You may need an appropriate loader to handle this file type.

hi @petyosi , my packages version:
"webpack": "^3.7.1",
"@babel/core": "^7.1.2",
"@babel/plugin-syntax-class-properties": "^7.0.0",
"@babel/plugin-syntax-dynamic-import": "^7.0.0",
"@babel/plugin-transform-runtime": "^7.1.0",
"@babel/polyfill": "^7.0.0-rc.2",
"@babel/preset-env": "^7.1.0",
"@babel/preset-react": "^7.0.0",

List does not re-render properly when backing data is shuffled/filtered.

I have created a codesandbox to illustrate the problem I'm having: https://codesandbox.io/s/wizardly-http-61djr. It's important to have the console open here to see the disparity between what "should" be rendered and what actually gets rendered.

In general, when a list is shuffled, <Virtuoso/> does not necessarily re-render in the correct order or render all of the items that it should. Instead, virtuoso seems to hold on to old values, even when computeItemKey is used.

I came to find this issue when working on a list that was filtered by text. Changing the text filter would change where some items should appear in the list, or whether they should appear at all. I.e. while typing a filter, an item that was previously at index 5 might end up at index 2, and an item previously at item 4 should no longer appear at all. In that particular example, I ended up getting in to a situation where the startIndex for some range always exceeded maxIndex here and so some items would not render at all after filtering caused a reduction in the overall size of a list. It seemed to be that for some items/nodes, old indices were being held that were outside the bounds of a new, reduced size list.

I'm curious whether this can be considered a bug or whether virtuoso is not meant to support the use case of a filterable list, a list that shuffles, etc.

[info] Always start at the bottom of the list

Hi! I'm building a chat system using React Virtuoso and I'm using scrollToIndex to scroll right to the bottom of the list, with a tiny delay. This works "ok" but as I said there's a tiny delay. I was wondering if there's a way to automatically show the list scrolled at the bottom already?

Thanks!

Strange behavior in Edge

Scrolling down, then up in Edge (Windows 10) behaves erratically, at least in a VM. The top items do not seem to be re-displayed properly.

FF and Chrome work as expected.

Question: Expose reportScrollTop or scrollTop in some way

Hi again,

For my use-case, I'm trying to have a 'back to top' button appear only when user scroll passed a certain limit in the list (most probably 2 x viewportHeight)

My first solution attempt was to position myself in the scrollingStateChange callback. And when the user stops scrolling, verify the scroller scrollTop and manage the button then. This method has some problems.

1- I have to declare a customer scroll component. Assign some ID to the div. In the scrollingStateChange, act only when the user stops scrolling, then fetch the scroller div with document.getElementById to determine its scrollTop value.
This works but does feel like a hack.

2- The button will only appear when the user stops scrolling. When usually this button will appear as soon as the trigger point get passed.

Maybe there is a nicer way to get this working already?

If not, would it be a good idea to expose an onScroll callback, supplying scrollTop as a parameter?

Thx a lot for all the help you've been providing. Its all very much appreciated.

TScrollContainer type missing children props

VirtuosoScroller.tsx

export declare type TScrollContainer = FC<{
    style: CSSProperties;
    className?: string;
    reportScrollTop: (scrollTop: number) => void;
    scrollTo: (callback: (scrollTop: number) => void) => void;
}>;

In VirtuosoScroller types is currently missing a children prop type, without this prop typescript will not allow you to pass in children to your custom scroll component.

An example of passing children down is shown here https://virtuoso.dev/custom-scroll-container/ but the given example uses merely javascript so typescript errors won't show here.

Auto size container height

An enhancement request - any chance of having the same autosizing as the width part?
Perhaps this is already doable via standard CSS things (like flex), but I can't seem to get it to work.
It would be useful to hard code a height of the scroll container, but also have it flex to fit the white space.
If the window changes size, or another component above changes size and pushes/pulls on the scroll container, it could automatically resize to only fill the white space.

This would be particularly useful for instances where the list takes up the whole width of the window, and it's annoying to have the window scroll and the list scroll right next to each other.

Running playground

I'm attempting to work on a previous issue that I have created, and would like to use playground to aid me in debugging. However, I'm having a couple of issues getting it to work.

First up, neither of the following dependencies can be resolved.

import { getUser } from '../../site/src/examples/FakeData'
import { UserItem } from '../../site/src/examples/ExampleComponents'

Second up, and this one is more on my limited experience in React, is how would you go about running the playground? Intuitively, I would want to run npm run playground but no playground script exists. Should I be running create-react-app in the playground directory? Something completely different?

App crashes when "list" is changed in VirtuosoGrid

first off, this library is great and exactly what I need!

I am using the VirtuosoGrid component, I supply it an array of small objects (from redux). I am trying to allow a user to use a text input to search and filter the boxes in the grid, so I have the text input text filter the array that is passed to this grid, when the list is "filtered" my react app crashes because a component that did have one of the "items" is now getting undefined.

I'm probably missing something simple. But it seems like this should just work?

// user typed in "mi"
const searchText = 'z';
const list = [{a: 'Mike'}, {a: 'Sam'}....... {a: 'Michael'}];

// some logic to filter the list based on text input
const filteredList = list.filter(item => item.a === searchText);

// down way below in renderland
<VirtuosoGrid
  totalCount={filteredList.length}
  item={idx => <MyComponent item={filteredList[idx]} />}
/>

Support Server-Side Rendering

FIrst off, this is a great library and I've got into one of our projects with massive traffic, so it will be stress-tested.

When creating a bunch of examples I discovered that while it doesn't break SSR specifically, but there is no way to support the server at the moment. The effects it triggers don't run in a server environment, so the component comes out empty when rendered on the server. This makes sense when you consider the lack of an actual window on the server, however in most applications rendering at least some content is much better than coming back with nothing, especially for SEO purposes and data retention.

I am aware of the limitations when it comes to windowing and a windowless Node instance, so I'm proposing the following:

  • Support SSR via a prop to declare amount of items to be rendered by default, or virtual window size to work with (maybe both, since both of these approaches have their pros and cons)
  • Introduce a hydration phase, where the component can gracefully take over rendering in a window, when it reaches a browser.

I can help brainstorm ideas or even contribute code if you like as I know that this is a larger addition.

Support for zero height rows

The application works wonderfully for me with material-ui ExpansionPanels. It correctly expands and closes the panel and moves/adjusts everything else in the list accordingly (unlike react-window or react-virtualize').
But unlike those other packages, if I need to hide a row (the expansion component only needs to be shown if a criterion is met) it fails. A zero height div, or a null object fails, and a 1px height div severely slows everything down.
Is there a way to deal with this, like to use the ItemContainer?

Changelog

Hi,

Is there a changelog for react-virtuoso?

Thanks

Scroll at specific index

Would like to see some features around scrolling to a specific index and an option to start at bottom.

Empty list when testing with react-testing-library

Hi, first of all, congrats for your awesome library! I've been trying to test some components where I use it, but the list never gets rendered 😞

import * as React from 'react';
import { Virtuoso } from 'react-virtuoso';
import {  render } from '@testing-library/react';

function Component () {
     return (
         <Virtuoso
                totalCount={100}
                item={index => <div>{index}</div>}
          />
     );
}

describe('Test', () => {
   it('should render list of items', () => {
        const { debug } = render(<Component />);
        debug(); // Prints an empty list
   });
});

Latest version (0.11) broken

When upgraded to the latest version (0.11), my app is not buildable by TypeScript because of the following error:

Property 'computeItemKey' is missing in type '{ totalCount: number; overscan: number; itemHeight: number; className: string; item: (index: number) => Element; }' but required in type 'Readonly<VirtuosoProps>'.

There is not a single mention about computeItemKey in the docs or the code examples

Latest version (0.12.0) broken

When upgraded to the latest version (0.12.0), my app is not buildable by TypeScript because of the following error:

TypeScript error in app/node_modules/react-virtuoso/dist/Virtuoso.d.ts(2,29):
Cannot find module 'tinyrx'.  TS2307

    1 | import React, { CSSProperties, FC, PureComponent, ReactElement } from 'react';
  > 2 | import { TSubscriber } from 'tinyrx';
      |                             ^
    3 | import { TScrollLocation } from './EngineCommons';
    4 | import { ListItem } from './GroupIndexTransposer';
    5 | import { TRender, TRenderProps } from './VirtuosoList';

I can see that react-virtuoso does not refer to the tinyrx as its dependency.

Property `item` of VirtuosoGrid called when `totalCount` is zero

When I set the totalCount of VirtuosoGrid to 0, nothing is rendered yet item is called. Is this expected behaviour?

Code snippet

ReactDOM.render(
    <VirtuosoGrid
        totalCount={0}
        item={index => {
            console.log(`item(${index})`);
            return <p>Item {index}</p>;
        }}
    />,
    document.getElementById('root')
);

Console log

item(0)

Alternate row color

Hi, I tried your component and works fast ! I wondered if we can add alternate row color using
&:nth-of-type(odd)

Since the item that we supply is inside another div, so it always @ 0 numbered row

Thanks

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.