Wrapping

A wrapping method must be specified for any Freighter carousel, and there are 3 to choose from.

What is Wrapping?

The term 'wrapping' in the context of a Freighter carousel is used to describe the behavior of a carousel when it is scrolled in either direction past the available elements. When a user scrolls to the last carousel items in your carousel, how should the container respond to another scroll to the right? This is the question that can be answered by the 'wrapping method' of your carousel.

The wrapping method for a Freighter carousel is indicated in the constructor, as the third parameter. See the code block below that demonstrates how to utilize the wrapping method wrap-simple in the carousel myCarousel:

const myCarousel = new Freighter(
  'myCarousel',     // Specify the container ID here.
  'none',           // Specify the desired resizing method here.
  'wrap-simple',    // Specify the desired wrapping method here.
  {},               // Dymamic properties can be specified here.
);
One important thing to note is that the wrapping is one of 3 carousel properties not specified within the CarouselProperties object passed to the constructor. This is because the CarouselProperties object only contains the properties that can be changed after the carousel is initialized. Wrapping is a fixed property that must be specified at initialization, and therefore does not belong inside of this object.

Wrapping Methods

Freighter offers 3 wrapping methods: none, wrap-simple, and wrap-smart. For the most part, these methods will behave as you might expect. There are a few quirks to each of them, however, that are worth noting.


none

The first and simplest wrapping method disallows scrolling to the left beyond the first item or scrolling to the right beyond the last item. This wrapping method guarantees that the order of carousel items will always be preserved; an carousel item with a lower index will never be displayed after an carousel item with a higher index. It also guarantees that the carousel will never display an empty space where an item should be.

Take for example the carousel created from the code below. This code presupposes that <div id="myCarousel"> already exists in the DOM, and has 9 carousel items as children. Notice that the carousel cannot be scrolled to the left until it has been scrolled right at least once.

const myCarousel = new Freighter(
  'myCarousel',
  'stretch-scale',
  'none',
  {
    numItemsVisible: 3,
    scrollBy: 3,
    itemSpacing: 15,
  },
);

This is all works fine. In the example above, the number of items (9) was evenly divisible by the scrollBy and numItemsVisible values (both 3). How would a carousel with a wrapping method of none behave if this isn't the case?

Let's start by increasing scrollBy to 4. This carousel can scroll to the right by 4 elements: the first scroll will set the visible elements to '5 6 7'. Attempting to scroll again would set the visible elements to '9 10 11' if they existed, but our carousel only contains 9 elements. Try scrolling the carousel to see how the wrapping method none behaves in this situation:

Clearly, wrapping method none does not scroll past the first or last element! This means that the scrollBy property is actually treated as the maximum number of elements that can be scrolled in either direction, but can be less than this if there are not enough elements to scroll that far.

What if there are fewer carousel items than the numItemsVisible value? Well, because there are no more elements to either the left or right of the currently visible elements, the carousel won't be able to scroll at all:

When items are added or removed from a carousel using the wrapping method of none, the 'empty space' principle must be maintained: the carousel must never display an empty space if an item is available to fill it.

Adding new items does not put the carousel in risk of violating this principle, but removing them does. What if a carousel with 9 items is scrolled all the way to the right (displaying '7 8 9'), and the last two items are removed? In order to preserve the 'empty space' principle, the carousel must be scrolled back to the left until all empty spaces are filled.

Try it for yourself - scroll to the end of the carousel, remove the last two elements, and see how the carousel is automatically shifted back in order to prevent the introduction of unneccesary empty slots.

The same is done with a carousel whose items are removed from the start when scrolled all the way to the left:


wrap-simple

The second wrapping method is more powerful that none, allowing for a simple infinite scrolling experience. The scrollBy value is always treated as the exact number of items to scroll by, regardless of how many items are available to scroll. This means that the carousel's absolute ordering of items may change, though its relative order will be preserved.

Below is the code required to set up a carousel with the wrap-simple wrapping method. This code presupposes that <div id="myCarousel"> already exists in the DOM, and has 9 carousel items as children. Try scrolling left from the first item, or right from the last item.

const myCarousel = new Freighter(
  'myCarousel',
  'stretch-scale',
  'wrap-simple',
  {
    numItemsVisible: 3,
    scrollBy: 3,
    itemSpacing: 15,
  },
);

Much like the wrapping method none, a carousel with a total number of items (9) that is evenly divisible by the scrollBy and numItemsVisible properties (both 3) works out nicely. Let's see how the carousel's behavior changes when this isn't the case. Below is the same carousel with a scrollBy value of 2:

In this case, you'll notice that it takes a few full traversals of the carousel for the '1 2 3' items to be restored. This is also the first time we've seen the carousel's absolute ordering of items change: scrolling left from the original position shows '8 9 1' as the visible carousel items.

Allowing wrapping with this method means that there is always a next (or previous) set of items to display in the carousel . As a result of this, carousels with the wrap-simple wrapping method will not have empty spaces. For example, take a look at the carousel below, which has a numItemsVisible of 4, but only 3 items in the carousel:

Because the carousel is allowed to wrap, it means that there will always be another item to add to the end of the carousel, and it will always be the first items in the carousel.

The behavior of the wrap-simple wrapping method means that carousel items may be duplicated in the DOM. If you inspect this page, you will notice that duplicate carousel items have the same IDs. If you write code that is dependent on the IDs of elements contained within carousel items, you may run into issues.

One way to avoid this issue is to ensure that the number of items in the carousel is always evenly divisible by the numItemsVisible and scrollBy values.

If you want your carousel to wrap, but you want the absolute order of carousel items to be preserved (i.e. not the previous example), you should make sure that the total number of items in the carousel is evenly divisible by the numItemsVisible and scrollBy values.

The ability to wrap around in either direction means that removing carousel items will never result in blank spaces in the carousel, unless the carousel is emptied completely:


wrap-smart

The third and final wrapping method is much easier to understand if you already know how the previous wrapping methods work. In short, wrap-smart is almost like the combination of the above wrapping methods. Like none, wrap-smart will initially treat scrollBy as a maximum, ensuring that scrolling will not disrupt the relative order of items in the carousel. However, once the end of the carousel is reached, wrap-smart will scroll by however much is needed to fully wrap to the other side of the carousel.

If this isn't clear at first, the examples below should help you understand what's going on.

First, here's how a carousel with the wrap-smart wrapping method can be created. Again, this code presupposes that <div id="myCarousel"> already exists in the DOM, and has 9 carousel items as children.

const myCarousel = new Freighter(
  'myCarousel',
  'stretch-scale',
  'wrap-smart',
  {
    numItemsVisible: 3,
    scrollBy: 3,
    itemSpacing: 15,
  },
);

Imediately, you'll notice that this carousel is behaving in exactly the same way as the one before it that used wrap-simple. This is true: both of the variations of wrap (wrap-simple and wrap-smart) behave the same when the number of carousel items is evenly divisible by the numItemsVisible and scrollBy values. Let's see what happens when we change scrollBy to be 2:

When the end of the carousel is hit (visible items are '7 8 9'), rather than just scrolling by the scrollBy value of 2, the carousel is scrolled by 3 so that the absolute positioning of carousel items does not change.

Let's try one more example, this time with a scrollBy value of 4:

Now, the amount that the carousel scrolls changes with each subsequent scroll! If you scroll right 3 times, the carousel will first scroll by 4, then 2, then 3. What's going on?

The wrap-smart wrapping method treats the scrollBy value as a maximum, meaning that it will always try to scroll that much, but may stop earlier to avoid scrolling past either end of the carousel. When one of the ends is reached, the next scroll will wrap over to the other end of the carousel as much as it needs in order to keep the absolute ordering of the carousel items. This is why this wrapping method is called wrap-smart: yes, your carousel will wrap, but it will do so intelligently in order to prevent items from losing their absolute ordering.

One of the most common use cases for this wrapping method is a carousel that only scrolls by 1 item, but should 'snap' back to the beginning when wrapping. Below is the code and resulting carousel for such a use case:

const myCarousel = new Freighter(
  'myCarousel',
  'stretch-scale',
  'wrap-smart',
  {
    numItemsVisible: 3,
    scrollBy: 1,
    itemSpacing: 15,
  },
);

No extra code, no event listeners for when the carousel hits the end, and no fear of the absolute order being altered.

There are a few cautions to be aware of when using wrap-smart, many of which are fully explained in their respective sections on the cautions page. These include carousels whose wrapping methods may change from wrap-smart to wrap-simple under specific circumstances , as well as the possibility of the absolute ordering being temporarily altered when adding or removing items.