Git Product home page Git Product logo

svelte-virtual-list's Introduction

svelte-virtual-list (demo)

A virtual list component for Svelte apps. Instead of rendering all your data, <VirtualList> just renders the bits that are visible, keeping your page nice and light.

Installation

yarn add @sveltejs/svelte-virtual-list

Usage

<script>
  import VirtualList from '@sveltejs/svelte-virtual-list';

  const things = [
    // these can be any values you like
    { name: 'one', number: 1 },
    { name: 'two', number: 2 },
    { name: 'three', number: 3 },
    // ...
    { name: 'six thousand and ninety-two', number: 6092 }
  ];
</script>

<VirtualList items={things} let:item>
  <!-- this will be rendered for each currently visible item -->
  <p>{item.number}: {item.name}</p>
</VirtualList>

start and end

You can track which rows are visible at any given by binding to the start and end values:

<VirtualList items={things} bind:start bind:end>
  <p>{item.number}: {item.name}</p>
</VirtualList>

<p>showing {start}-{end} of {things.length} rows</p>

You can rename them with e.g. bind:start={a} bind:end={b}.

height

By default, the <VirtualList> component will fill the vertical space of its container. You can specify a different height by passing any CSS length:

<VirtualList height="500px" items={things} let:item>
  <p>{item.number}: {item.name}</p>
</VirtualList>

itemHeight

You can optimize initial display and scrolling when the height of items is known in advance. This should be a number representing a pixel value.

<VirtualList itemHeight={48} items={things} let:item>
  <p>{item.number}: {item.name}</p>
</VirtualList>

Configuring webpack

If you're using webpack with svelte-loader, make sure that you add "svelte" to resolve.mainFields in your webpack config. This ensures that webpack imports the uncompiled component (src/index.html) rather than the compiled version (index.mjs) โ€” this is more efficient.

If you're using Rollup with rollup-plugin-svelte, this will happen automatically.

License

LIL

svelte-virtual-list's People

Contributors

benmccann avatar jacwright avatar mhkeller avatar mustafa0x avatar rich-harris 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

svelte-virtual-list's Issues

Two bugs?

Hi there.
First of all thanks for that cool lib. And a big thank you for Svelte.
Thanks to Svelte i am, as a beginner (not a year or so), am able to code this awesome dapp by myself mostly https://cloudatlas.club

I actually "abuse" Svelte as a Compiler only. I always start like npm install vite@latest, choose Svelte/TS, and use only JAM (Typescript) and NOTHING svelte specific but the bindings ๐Ÿ˜ The bundler rewards me with Vanilla JS at the end which can be dropped on edge, and npm run dev hot-reload loads in milliseconds, even if the project gets bigger. The app itself is small and lightspeed.

So big Thank You. ๐Ÿ™๐Ÿ™๐Ÿ™

(Bug?) 1: I use Virtual List on the website above and i noticed, and got addressed by some users, that the scroll stucks / glitches a bit. Also after clicking on one of the bottom cards, a new tab opens, and the VL closes, and when you then click on the dapp-store text field again, everything above the last shown section is not loaded and you need to scroll down, then it starts from the begin.

Normal

image

After new tab opens and VL closes (you can tell by the above picture and the bottom scrollbar this is not right)

image

Now i wonder if my seach filter and / or the function for closing the VL after click, is maybe causing this or if this is something that VL causes???
Here is the code: https://github.com/worldpeaceenginelabs/METAVERSE-DAO_CLOUD-ATLAS/tree/master/src/Appsearch

(Bug?) 2: in the data.js i add records (dapp-store cards) manually. with \ i can escape characters, but \n should start a new line or not? Because it does not! :(

Expose the view port scroll event

I am implementing a grid using the virtual list.

Case:
The width of the container is fixed but the user can resize column widths making the inner content horizontally scrollable. To keep the header in sync with the content I want to get the scrollLeft value.

Current Behavior:
VirutalList does not expose the scroll event of svelte-virtual-list-viewport.

Expected Behavior:
Scroll event should be exposed.

[group] control scroll position

This is a summary of issues around similar use-cases:

  • #15 lazy loading: [bug, resolved?] adding more items keeps scroll position and increases scroll length below
  • #28 scroll to song: bring an item (by index) into view
  • #30 filtering list: [bug] removing more items than current scroll position assumes causes "empty" viewport
  • #32 messenger: autoscroll to bottom if new items loades

I hope the use-case-namings are helpful - all these issues have in common, that we expect certain behaviours from the scroll position. To prevent solving one issue while re-creating another, I suggest to work towards one PR that solves them together ๐Ÿš„ ๐Ÿค

REPL: https://svelte.dev/repl/1c36db7c1e7e4ef2bfb04874321412e5?version=3.20.1


comparable vanilla implementations:

It doesn't seem to work with Semantic HTML

I was wondering if there's a way to make VirtualList support tags like <ul> to be the list a container having <li>s as list items or how can a <table> be rendered using it?

Best way of adding padding to the first list item

I want to add padding to the first item of the list, or fake it somehow, but bottom line is that I want to avoid clipping like this
image

In android I would do that with clipToPadding false, but I wasn't able to find alternative for css. I thought of maybe targeting the first child of the list, but the the list is nested multiple times. Any ideas?

List isn't being populated

Maybe I'm doing something wrong but basically I'm trying to create a virtual list of images after a fetch call. It was working before without the virtual list but now it doesn't. It doesn't seem to be populating the List.

Here is the code I am using, lemme know if I'm just an idiot or this is a real issue.

<script>
  import VirtualList from '@sveltejs/svelte-virtual-list';

  export let results = [];
  $: results;
</script>

{#if results.length}
<VirtualList items={results} let:result>
  <div class="fl pa2 w-50 w-20-ns">
      <a href={result.url} class="db aspect-ratio aspect-ratio--1x1 dim">
        <div style="background-image: url('{result.images.original.url}')" class="bg-center cover aspect-ratio--object">
        </div>
      </a>
  </div>
</VirtualList>
{/if}

Can we deploy this with npm?

Would it be possible to make it so we can npm install this app?

There's nothing wrong yarn, many svelte apps on the REPL are available with npm, and getting yarn adds an extra step.

List is not accessible

Hello, and thank you for your library! We use it here at nylas.com

However, we've found out user can't use keyboard arrow keys to navigate the list. Is this something easy to fix?

Img tags without height causes issues.

Enhancement request:

Support dynamic row height based off that autoscale height.

Issue
When images load within virtual list row and expand the height when no height attribute is set - causes issues with scrolling to become jagged.

Fix
Setting a fixed height on images resolves the issue.

Proposed
Is it possible to add support to listen for image loads that change the height of the row?

Thanks

Supports svelte v3?

Is the svelte-virtual-list supporting svelte v3?

I am passing props in, but the VirtualList seems to listen to data is this a known change between v2 and v3?

image

Regards,
JP

Feature request: Initial "start" value (auto-scroll to certain element)

I really need to auto-scroll the list to remembered position. But the algorythm is kinda complicated. So I failed to do it myself so far. Maybe somebody can give me a hint how to achieve this behaviour. Or even make it if it is not so complicated.

I did almost all needed changes (as I think :)), but part after "prevent jumping if we scrolled up into unknown territory" is ruin everything, since I don't know previous row heights.

Thank you!

Diff by my code so far: https://github.com/sveltejs/svelte-virtual-list/compare/master...Kreozot:initial-position?expand=1

Passing props down to rows

Currently, the row component can only access row, which means no information about the outside world โ€” for example, we can't highlight some text that's being used to filter rows, because we can't pass down the filter text.

Maybe something like this:

<VirtualList items={{...}} component={{...}} props='{{ { foo, bar } }}' />

Then, it would be passed to the row like so:

<:Component {component} {{...props}} row={{item.data}} />

The props= is a little unfortunate, especially since it means having a clusterfuck of curly braces. This is one place where the React model wins, because you can do this:

const { items, component, ...props } = this.props;

return visible.map(item =>
  <Component {...props} row={item.data} />
);

In Svelte there isn't a great way to accomplish that. Even the {{...this}} proposal (sveltejs/svelte#1303) doesn't really help, though I suppose it'd be possible to do this:

<:Component {component} {{...(exclude(this, ['items', 'component'])}} row={{item.data}} />

Height option

The viewport defaults to height: 100% which typically means you need a wrapper element with a set height. Might be convenient if that was configurable, defaulting to 100%:

<VirtualList height='400px' items=... component=... />
<VirtualList height='calc(100vh - 5em)' items=... component=... />

JS Code in items slow down page scrolling

Having list items with heavy js usage on initialization will lead to a buggy scroll experience.

As example I had a VirtualList with 8 columns and each item was using some jquery code to call a function from semantic ui:
window.$(cardItem).children('.inlinepopup').popup();

The popup was called when the item got initialized the first time, but when I scrolled down and up it doesnt. Therefore I wrapped it in a onMount function. That lead to a very laggy scroll experience.

I worked arround this by introducing a finished variable, which tells if the user is still scrolling or has finished/paused for at least 800ms:

VirtualList.svelte

export let finished = true;
let lastUpdate = Date.now();

async function handle_scroll() {
		finished = false;
// โ€ฆ whole existing handle_scroll() function here
		lastUpdate = Date.now();
}

$: {
        if(!finished && (lastUpdate + 800) < Date.now() ) {
            finished = true;
        } else if(!finished) {
            setTimeout(() => {
                lastUpdate = lastUpdate - 1
            }, 900);
        }
}

App.svelte

<VirtualList {items} let:item bind:finished>
	<ListItem  {item} {finished} />
</VirtualList>

ListItem.svelte

    export let finished;
    let initialized = false;

    $: {
        if(!initialized && finished ) {
            window.$(cardItem).children('.inlinepopup').popup();
            initialized = true;
        }
    }

If this is a good idea, I could open an PR.
Edit: maybe finished should be isScrolling instead with inverse boolean.

Support multiple items per row

It would be great if this also could support multiple items per row, to enable grid-like views.

Would you be interested in expanding VirtualList to take an itemsPerRow parameter?

<VirtualList items={items} itemsPerRow={3} />

Viewport goes empty if scrolled down and items array changes.

So I decided to try to work with this component and add a filteredItems function that filters depending on some input.

It appears as though the viewport is not scrolled to the top when the items array changes which results in some weird behaviour. I have showcased it in this REPL

To reproduce, scroll down some hundreds of items and start writing something in the input field.

The solution is simple and I will make a PR.

Unique identifier stability problem when changing the list.

This virtual list is a remarkably concise code for what it does. Thanks, RIch.

I started using it in a test app in which I am showing database content. I hit a little problem when my data is altered (from a push from another editor) and the update gives a rather strange result.
I think it is rooted in the few lines of code in the {#each visible as row (row.index)} block. The id for each item is simply the row.index.
The example has a key variable to the data. Could it, or another data (id ?) in the array serve as a unique id for each object's rendering ?

All items get rendered

I've created a fresh project using the latest svelte, and it looks like if itemHeight isn't set that some limited set amount of components get added to the DOM but never updates on scroll. If itemHeight is not set, all the items get rendered all the time, even if they are far off screen.

EDIT: it seems like if I set the Height property in pixels that the items get rendered, but it generates a nested scrollbar for the container of the item elements.

autoscroll (to the bottom) feature

It could be nice to have the the autoscroll to the bottom.
Attached you can see the implementation (copied and pasted from the tutorial of svelte):
VirtualList.svelte.txt

Usage:

<VirtualList items={$chatMessages} bind:start bind:end let:item autoscroll={true}> <Message msg={item}/> </VirtualList>

Thank you

Emanuele

Importing this component into an unmodified sapper w/ rollup project results in this error

node_modules/@sveltejs/svelte-virtual-list/VirtualList.svelte:1
<script>
^

SyntaxError: Unexpected token <
    at Module._compile (internal/modules/cjs/loader.js:720:22)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:788:10)
    at Module.load (internal/modules/cjs/loader.js:643:32)
    at Function.Module._load (internal/modules/cjs/loader.js:556:12)
    at Module.require (internal/modules/cjs/loader.js:683:19)
    at require (internal/modules/cjs/helpers.js:16:16)
    at Object.<anonymous> (/mnt/shared/dev/comicsub/__sapper__/dev/server/server.js:11:35)
    at Module._compile (internal/modules/cjs/loader.js:777:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:788:10)
    at Module.load (internal/modules/cjs/loader.js:643:32)```

Documentation example should include a container with height

I was having a lot of trouble getting this working until I learned that the VirtualList component needs to be wrapped in a container with height. Correct me if I'm wrong. This isn't mentioned anywhere in the documentation and I think it should be included in the basic example.

Propagate events

The corollary to #4 โ€” there's currently no way to listen for events coming from a row component. One way would be to have a single catch-all event:

<VirtualList on:event='handleEvent(event)' ... />

In that situation, the row component would need to do this sort of thing:

<div on:click="fire('event', { type: 'select', row })">
  <!-- row markup here -->
</div>

It would be slightly nicer if the row component could look like this...

<div on:click="fire('select', { row })">
  <!-- row markup here -->
</div>

...but that would require some new way to propagate all events:

<:Component {component} on:* row={{item.data}} />

Expensive mounting

What is the recommended strategy to deal with components that are expensive (aka slow) to remount? Is there a way to keep the state of the 'offscreen' items in memory, or, the first ~10 invisible items at the top and the first ~10 invisible items at the bottom? I'm having trouble figuring out how to do this. I'm not sure whether I can do it without making any changes to the VirtualList.svelte component.

<VirtualList items={items} let:item bind:start bind:end> <ExpensiveComponent /> </VirtualList>

Get index of the item

Hi,

We can set a let:item , is there a way to retrieve the index when looping through the items.

Thanks a lot.

Kindest regards,

Lisa

List gets broken when its offscreen

Hey,
nice virtual-list! Thank you!
Unfortunately I found some issues...

  1. When the 'items' property changes and the virtual-list is off-screen (ex. display:none) the list never gets filled again with items :/
    see: https://svelte.technology/repl?version=2.13.4&gist=b31acc26d0b807323fd3271e2d634b0c
    The problem occurs, when you first add the data and then show the virtual-list :/
    Afterwards, when I refresh the list or set other data while the list is visible, some errors like in point 2 are thrown. After that all onstate calls are blocked because of this issue:
    sveltejs/svelte#1717
  2. If you scroll up very fast, the virtual-list throws some errors:
    "TypeError: this.rows[(i - newStart)] is undefined"
    thats not an issue at all, but fair to point out!

Any chance to fix these? Or is there a workaround?

Thank your for your time!

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.