Skip to main content

Horizontal lists (Lesson 4.7)

Horizontal lists allow us to display a row of items that the user can scroll with their finger. They’re a super versatile element!

Sofia Maconi avatar
Written by Sofia Maconi
Updated over 2 weeks ago

Transcript

In this lesson, we're going to set up this horizontal scrolling carousel of diary entry images on our trip details view.

So, our current trip details view looks like this — and we're going to put our carousel of images right here.

Now, it's worth noting that at the time of recording, the mobile beta does not have a carousel that behaves like this one on trip.com, where I can simply swipe with my finger to go to a different image in the carousel. If by the time you're watching this there is a carousel available, we'll let you know in the description for this video.

The element that we're going to be using for our carousel is actually this element called a horizontal list. So, I'm going to grab that and put it here in my group body, and I'm going to drag it to the top.

Let's first try to understand how this element works. We've got a type of content here — let's say, for sake of argument, I’ll set this to be a diary entry for now. Then we've got a data source, and in this data source, I need to retrieve a list of whatever thing is chosen at the top here.

So, diary entries. I could, for example, do a search for all of the diary entries where the trip is the current view’s trip — in other words, all of the diary entries belonging to the current trip. So:
trip = trip details trip.

Now, inside of the horizontal list, we’ve got a setup that’s very similar to our vertical list — in that our vertical list has a vertical list item holding a single entry in that list (a single row, in the case of a vertical list). It’s the same thing for a horizontal list, only a horizontal list item holds a column instead of a row.

So, this is our horizontal list item. Whatever we define within this item will be replicated for every entry in this list. For example, if I show the placeholder text that Bubble has given me and choose the current item’s diary entry title, you can see that reflected automatically in the other entries in the list.

Let’s get rid of the supporting text for now. You can see here — on one of the trips we created earlier — we’ve got a bunch of diary entries appearing in this horizontal list, which I can scroll across with my finger.

Now, it’s worth pointing out: this horizontal list is not designed to hold a huge amount of data. Only our vertical list is optimized behind the scenes to handle lots and lots of data.

That’s because what Bubble will do intelligently is, as the user scrolls, it will load in the data as needed — only loading what’s visible on screen.

That’s not so with a horizontal list element. With a horizontal list, as soon as the view is loaded, all of the elements needed to populate this list — that is, whatever data is returned by the search — are all loaded at once when the view is shown.

So, if you’re loading 10,000 entries (comments, posts, whatever), that’s a lot of data. A mobile device isn’t designed to hold that much — limited power, limited memory.

So if you are loading a huge amount of data (like Instagram or TikTok-style infinite scrolling), you should use a vertical list, because Bubble will only load the first 10 entries it needs, then load the next 10 as the user scrolls — that’s called lazy loading.

In our case, though, we don’t want to show diary entries themselves — we’re already doing that below in the vertical list. Up here, we want to display the images from those diary entries.

So let’s delete the text element and rename this horizontal list to Horizontal List Images.

The type of content here I’ll set to be image — so it’s a list of images.

The data source we set up (searching for all diary entries for the current trip) is actually correct as the starting point — because conceptually, we’re grabbing all the diary entries, and then for each diary entry that has an image, we want to pull that image out and display it here.

The way we write that in Bubble is:
Search for Diary EntriesEach item's image

So, what this does is: it pulls out a list of diary entries from our database, then extracts the images attached to each of those diary entries. We end up with a list of images, which is exactly what this horizontal list is configured to accept.

Now that we have that data source, we can tell the horizontal list item — that’s each individual cell — to display its image as a background.

So, for the background style, choose Image, and set the dynamic image to the current item’s image.

We’ll center it and crop it as usual.

If we load this up for our Italy backpacking trip, we’ll see one image — the only one we have, since we only have one diary entry with an image.

Let me just create a few extra diary entries so we can see more data.

Okay — I’ve added a few new entries, and now you can see the behavior of this horizontal list.

One thing to note: if I add a diary entry without an image, it creates an empty space in the horizontal list. That’s because our data source searches for all diary entries, then displays each of their images — even if there isn’t one.

We can fix that by adding another search constraint to make sure we’re only returning diary entries that actually have an image:
Image is not empty.

That fixes it.

Now, let’s clean up the design a bit. We’ve got a bit of padding on either side that we don’t need — this list already lives inside Group Body, which has padding.

We also have only 150px of height — I’ll bump that up to 400px.

For the horizontal list item, I’ll set a fixed width of 320px.

This gives us a nice vertical photo layout — 320 wide by 400 high. That ratio works well for portrait-style phone photos, which most users will likely upload.

320px also fits comfortably on most modern screens — older small iPhones used 320px widths, but we have padding anyway, so this is fine.

Here’s how it looks now — pretty good. The next image peeks in from the right side, which subtly signals that the user can scroll — I like that.

The only thing I’d change is that the trip title looks better below the images.

Right now, the title is appearing in the app bar. So I’ll right-click on it, clear it out, and change the title style to centered, so we don’t add extra space below the icons.

Then, just like in our diary entry details view, I’ll add a text element inside Group Body, just above the trip type badge.

This text will display the trip’s title (from the trip details view → trip → title).

I’ll add a placeholder so we can preview it.

Let’s make it more prominent — maybe use Heading 4, and remove the minimum height.

That looks good. I might still tighten up some spacing — there’s too much space below and between some of these elements.

That extra space looks like it’s caused by the summary text element, which has a minimum height of 44.

If I double it to 88, you can see the gap increase — so I’ll remove the minimum height entirely.

To be safe, I’ll also make that summary text only visible when there’s actually a summary:

When trip summary is not empty → visible.

When it’s hidden, it collapses, taking up no space — perfect.

That solves the gap issue.

Now, let’s make a few final adjustments. I want to bring the top section closer together — these elements (the title, summary, and metadata) are all related, so they should be grouped visually.

I’ll reduce the row gap between those elements, and then add some bottom margin (let’s say 24px) below the group body before the vertical list starts.

That looks much better.

The only other tweak I’ll make is to emphasize the diary entry titles — right now they blend in with the trip metadata.

I’ll increase their font weight, and you can see the difference — it’s clearer these belong to a different category.

Now, when I click on one of these images, I’m taken to the corresponding diary entry — and we can really see this app coming to life.

The last thing we’ll do, in terms of displaying images, is add some kind of image to our list of trips, so it looks a little more like this.

We’ll learn how to do that in the next lesson.

Did this answer your question?