ActiveList Concepts

1. Overview

The ActiveList is a component that can represent a large number of user interface elements. Here are some examples:

A. Tabs

A tabs component for which one tab can be active at a time.

A list of all players both friends and enemies.
View code
import { ActiveList } from '@uiloos/core';

const tabsEl = document.querySelector('.tabs-example');
const buttonsEl = tabsEl.querySelectorAll('.tab');
const contentsEl = tabsEl.querySelectorAll('.tab-content');

const config = {
  contents: ['all', 'friends', 'active'],
  active: ['all']
};

function subscriber(tabs) {
  buttonsEl.forEach((buttonEl, index) => {
    if (index === tabs.lastActivatedIndex) {
      buttonEl.classList.add('active');
    } else {
      buttonEl.classList.remove('active');
    }
  });

  contentsEl.forEach((contentEl, index) => {
    if (index === tabs.lastActivatedIndex) {
      contentEl.classList.remove('visually-hidden');
      contentEl.ariaHidden = false;
    } else {
      contentEl.classList.add('visually-hidden');
      contentEl.ariaHidden = true;
    }
  });
}

const tabs = new ActiveList(config, subscriber);

buttonsEl.forEach((buttonEl, index) => {
  buttonEl.onclick = () => tabs.activateByIndex(index);
});
<div class="tabs-example">
  <div class="tabs-container">
    <button class="tab active">All</button>
    <button class="tab">Friends</button>
    <button class="tab">Enemies</button>
  </div>

  <div class="tab-content" aria-hidden="false">
    A list of all players both friends and enemies.
  </div>
  <div class="visually-hidden tab-content" aria-hidden="true">
    A list of your friends
  </div>
  <div class="visually-hidden tab-content" aria-hidden="true">
    A list of your enemies
  </div>
</div>
.tabs-example {
  border-color: black;
  border-width: 1px;
  margin-bottom: 16px;
}

.tabs-example .tabs-container {
  display: flex;
  margin-bottom: 16px;
  border-width: 1px;
  margin-bottom: 16px;
}

.tabs-example .tab {
  color: black;
  padding: 1rem;
  background-color: white;
  flex-grow: 1;
}

.tabs-example .tab.active,
.tabs-example .tab:hover {
  background-color: rgb(192 132 252);
  color: rgb(255 255 255);
}

.tabs-example .tab-content {
  padding: 16px;
}
B. Segmented button

A segmented button component which is a horizontal group of buttons, from which only one can be selected at a time.

Lorem ipsum dolor sit amet consectetur adipisicing elit. Fuga commodi tenetur dignissimos maxime reprehenderit quam hic, molestiae nisi dolorem nihil dolor illum asperiores incidunt distinctio quod modi, corporis quae neque!

View code
import { ActiveList } from '@uiloos/core';

const segmentEl = document.querySelector('.segment-example');
const buttonsEl = Array.from(
  segmentEl.querySelectorAll('button')
);

const config = {
  contents: buttonsEl,
  active: buttonsEl.filter(
    (b) => b.classList.contains('active')
  ),
};

function subscriber(segmentedButton) {
  segmentedButton.contents.forEach((content) => {
    const buttonEl = content.value;

    if (content.isActive) {
      buttonEl.classList.add('active');
    } else {
      buttonEl.classList.remove('active');
    }
  });
}

const segmentedButton = new ActiveList(config, subscriber);

buttonsEl.forEach((buttonEl) => {
  const actualOnClick = buttonEl.onclick;

  buttonEl.onclick = (event) => {
    segmentedButton.activate(buttonEl);
    actualOnClick(event);
  };
});
<div class="segment-example">
  <div class="segment-container">
    <button onclick="left()" class="active">Left</button>
    <button onclick="center()">Center</button>
    <button onclick="right()">Right</button>
  </div>

  <p id="segment-example-text">
    Lorem ipsum dolor sit amet consectetur adipisicing 
    elit. Fuga commodi tenetur dignissimos maxime 
    reprehenderit quam hic, molestiae nisi dolorem nihil 
    dolor illum asperiores incidunt distinctio 
    quod modi, corporis quae neque!
  </p>
</div>

<script defer="true">
  const pEl = document.getElementById('segment-example-text');

  function left() {
    pEl.style.textAlign = 'left';
  }

  function center() {
    pEl.style.textAlign = 'center';
  }

  function right() {
    pEl.style.textAlign = 'right';
  }
</script>
.segment-example {
  margin-bottom: 16px;
}

.segment-example .segment-container {
  display: flex;
  display: flex;
  justify-content: center;
}

.segment-example button {
  color: white;
  padding: 8px;
  background-color: rgb(192 132 252);
}

.segment-example button.active,
.segment-example button:hover {
  color: white;
  background-color: #6b21a8;
}

.segment-example .tab-content {
  padding: 1rem;
}

.segment-example p {
  padding: 0 64px;
  margin: 16px 0;
}
C. Accordion

An accordion component from which the user can open one item at a time.

What is the meaning of life?

Lorem ipsum dolor sit amet consectetur adipisicing elit. Fuga commodi tenetur dignissimos maxime reprehenderit quam hic, molestiae nisi dolorem nihil dolor illum asperiores incidunt distinctio quod modi, corporis quae neque!

How many eggs are in the basket?

Lorem ipsum dolor sit amet consectetur adipisicing elit. Fuga commodi tenetur dignissimos maxime reprehenderit quam hic, molestiae nisi dolorem nihil dolor illum asperiores incidunt distinctio quod modi, corporis quae neque!

Who dunnit?

Lorem ipsum dolor sit amet consectetur adipisicing elit. Fuga commodi tenetur dignissimos maxime reprehenderit quam hic, molestiae nisi dolorem nihil dolor illum asperiores incidunt distinctio quod modi, corporis quae neque!

View code
import { ActiveList } from '@uiloos/core';

const accordionEl = document.querySelector('.accordion-example');
const detailsEl = Array.from(accordionEl.querySelectorAll('details'));

const config = {
  contents: detailsEl,
  active: detailsEl.filter((detail) => detail.getAttribute('open') === 'open'),
  maxActivationLimit: 1,
};

function subscriber(accordion) {
  accordion.contents.forEach((content) => {
    const detailEl = content.value;
    detailEl.open = content.isActive;
  });
}

const accordion = new ActiveList(config, subscriber);

detailsEl.forEach((detailEl) => {
  detailEl.onclick = (event) => {
    // Prevent default opening of details subscriber handle this. 
    event.preventDefault();

    accordion.activate(detailEl);
  };
});
<div class="accordion-example">
  <details>
    <summary>What is the meaning of life?</summary>
   
    <p>
      Lorem ipsum dolor sit amet consectetur adipisicing 
      elit. Fuga commodi tenetur dignissimos maxime 
      reprehenderit quam hic, molestiae nisi dolorem nihil 
      dolor illum asperiores incidunt distinctio 
      quod modi, corporis quae neque!
    </p>
  </details>

  <details open="open">
    <summary>How many eggs are in the basket?</summary>

    <p>
      Lorem ipsum dolor sit amet consectetur adipisicing 
      elit. Fuga commodi tenetur dignissimos maxime 
      reprehenderit quam hic, molestiae nisi dolorem nihil 
      dolor illum asperiores incidunt distinctio 
      quod modi, corporis quae neque!
    </p>
  </details>

  <details>
    <summary>Who dunnit?</summary>

    <p>
      Lorem ipsum dolor sit amet consectetur adipisicing 
      elit. Fuga commodi tenetur dignissimos maxime 
      reprehenderit quam hic, molestiae nisi dolorem nihil 
      dolor illum asperiores incidunt distinctio 
      quod modi, corporis quae neque!
    </p>
  </details>
</div>
.accordion-example {
  margin-bottom: 16px;
}

.accordion-example details {
  margin: 16px 0px;
}

.accordion-example summary {
  font-weight: bold;
  cursor: pointer;
  list-style: none;
}

.accordion-example details[open] summary {
  color: #6b21a8;
}

.accordion-example details summary::before {
  margin-right: 8px;
  font-family: 'Courier New', Courier, monospace;
}

.accordion-example details[open] summary::before {
  content: "-";
}

.accordion-example details summary::before {
  content: "+";
}

.accordion-example p {
  margin-left: 20px;
}
D. Carousel

A carousel shows the user a single slide at a time and will autoPlay to the next slide automatically.

View code
import { ActiveList } from '@uiloos/core';

const carouselEl = document.querySelector('.carousel-example');
const slidesEl = Array.from(
  carouselEl.querySelectorAll('.slide')
);

const config = {
  contents: slidesEl,
  active: slidesEl[0],
  autoPlay: {
    duration: 5000
  },
  isCircular: true
};

function subscriber(carousel) {
  carousel.contents.forEach((content) => {
    const slideEl = content.value;

    if (content.isActive) {
      slideEl.classList.add('fade-in');
      slideEl.classList.remove('fade-out');
    } else {
      slideEl.classList.remove('fade-in');
      slideEl.classList.add('fade-out');
    }

    slideEl.ariaHidden = !content.isActive;
  });
}

const carousel = new ActiveList(config, subscriber);
<div class="carousel-example">
  <div class="slide" aria-hidden="false">
    Slide 0
  </div>

  <div class="slide" aria-hidden="true">
    Slide 1
  </div>

  <div class="slide" aria-hidden="true">
    Slide 2
  </div>

  <div class="slide" aria-hidden="true">
    Slide 3
  </div>
</div>
.carousel-example {
  margin-bottom: 16px;
  position: relative;
  height: 200px;
}

.carousel-example .slide {
  position: absolute;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 200px;
  font-size: 64px;
  transition: opacity 0.4s linear;
}

.carousel-example .slide:nth-child(even) {
  color: white;
  background-color: rgb(192 132 252);
}

.carousel-example .slide:nth-child(odd){
  color: black;
  background-color: lightgray;
}

.carousel-example .slide.fade-in {
  opacity: 1;
}

.carousel-example .slide.fade-out {
  opacity: 0;
}
E. Sortable

A list which can be sorted by the user.

0 / 6 todo's are done
View code
import { ActiveList } from '@uiloos/core';

const exampleEl = document.querySelector('.sortable-example');
const sortableEl = exampleEl.querySelector('.sortable');
const sortableEls = Array.from(
  exampleEl.querySelectorAll('.sortable-item')
);
const noFinishedEl = exampleEl.querySelector('#no-finished');

const config = {
  contents: sortableEls,
  maxActivationLimit: false
};

function subscriber(sortable, event) {
  if (event.type === 'INITIALIZED') {
    return;
  }

  if (event.type === 'MOVED' || event.type === 'SWAPPED') {
    sortableEl.textContent = '';

    sortable.contents.forEach((content) => {
      sortableEl.append(content.value);
    });
  } else {
    sortable.contents.forEach((content) => {
      const todoEl = content.value;

      if (content.isActive) {
        todoEl.classList.add('done');
      } else {
        todoEl.classList.remove('done');
      }

      noFinishedEl.textContent = sortable.activeContents.length;
    });
  }
}

const sortable = new ActiveList(config, subscriber);

let draggedElement = null;

sortableEls.forEach((sortableEl) => {
  sortableEl.draggable = true;

  sortableEl.ondragstart = (event) => {
    event.dataTransfer.effectAllowed = 'move';

    draggedElement = sortableEl;
  };

  sortableEl.ondragover = (event) => {
    event.preventDefault();

    const toIndex = sortable.getIndex(sortableEl);
    sortable.move(draggedElement, toIndex);
  };

  sortableEl.ondrop = (event) => {
    event.preventDefault();
  };

  // Make reorder buttons work
  const [upEl, downEl] = sortableEl.querySelectorAll('button');

  upEl.onclick = () => {
    const index = sortable.getIndex(sortableEl);

    sortable.contents[index].swapWithPrevious();
  };

  downEl.onclick = () => {
    const index = sortable.getIndex(sortableEl);

    sortable.contents[index].swapWithNext();
  };

  // Handle the checked logic
  const inputEl = sortableEl.querySelector('input');
  inputEl.onchange = (event) => {
    if (event.target.checked) {
      sortable.activate(sortableEl);
    } else {
      sortable.deactivate(sortableEl);
    }
  };
});
<div class="sortable-example">
  <div class="sortable">
    <div class="sortable-item">
      <label>
        <input type="checkbox"/>
        Eggs
      </label>

      <div class="buttons">
        <button></button>
        <button></button>
      </div>
    </div>
    <div class="sortable-item">
      <label>
        <input type="checkbox"/>
        Leeks
      </label>

      <div class="buttons">
        <button></button>
        <button></button>
      </div>
    </div>
    <div class="sortable-item">
      <label>
        <input type="checkbox"/>
        Milk
      </label>

      <div class="buttons">
        <button></button>
        <button></button>
      </div>
    </div>
    <div class="sortable-item">
      <label>
        <input type="checkbox"/>
        Strawberries
      </label>

      <div class="buttons">
        <button></button>
        <button></button>
      </div>
    </div>
    <div class="sortable-item">
      <label>
        <input type="checkbox"/>
        Apples
      </label>

      <div class="buttons">
        <button></button>
        <button></button>
      </div>
    </div>
    <div class="sortable-item">
      <label>
        <input type="checkbox"/>
        Potatoes
      </label>

      <div class="buttons">
        <button></button>
        <button></button>
      </div>
    </div>
  </div>

  <small>
    <span id="no-finished">0</span> / 6 todo's are done
  </small>
</div>
.sortable-example {
  margin-bottom: 16px;
}

.sortable {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.sortable-example .sortable-item {
  padding: 8px;
  border: solid 1px lightgray;
  cursor: grab;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.sortable-example .sortable-item.done {
  opacity: 0.4;
}

.sortable-example .sortable-item label {
  display: flex;
  align-items: center;
  gap: 16px;
}

.sortable-example .sortable-item.done label {
  text-decoration: line-through;
}

.sortable-example .sortable-item .buttons {
  align-self: flex-end;
  display: flex;
  gap: 8px;
}
F. Gallery

An image gallery shows multiple images and allows the user to select one which is displayed larger than the others.

View code
import { ActiveList } from '@uiloos/core';

const galleryEl = document.querySelector('.gallery-example');
const buttons = Array.from(galleryEl.querySelectorAll('button'));
const selectedEl = galleryEl.querySelector('.gallery-selected');

const config = {
  contents: buttons,
  active: buttons[0],
};

function subscriber(carousel) {
  const activeButton = carousel.lastActivated;

  const pictureEl = activeButton.querySelector('picture');

  selectedEl.innerHTML = '';
  selectedEl.append(pictureEl.cloneNode(true));
}

const carousel = new ActiveList(config, subscriber);

buttons.forEach((button) => {
  button.onclick = () => {
    carousel.activate(button);
  };
});
<div class="gallery-example">
  <div class="gallery-selected"></div>

  <ul>
    <li>
      <button>
        <picture>
          <source type="image/avif" srcset="/images/owls/snow.avif" />
          <img width="1920" height="1280" src="/images/owls/snow.jpg" alt="image of a snow owl" />
        </picture>
      </button>
    </li>
    <li>
      <button>
        <picture>
          <source type="image/avif" srcset="/images/owls/tawny.avif" />
          <img width="1920" height="1280" src="/images/owls/tawny.jpg" alt="image of a snow owl" />
        </picture>
      </button>
    </li>
    <li>
      <button>
        <picture>
          <source type="image/avif" srcset="/images/owls/barn.avif" />
          <img width="1920" height="1280" src="/images/owls/barn.jpg" alt="image of a barn owl" />
        </picture>
      </button>
    </li>
    <li>
      <button>
        <picture>
          <source type="image/avif" srcset="/images/owls/burrowing.avif" />
          <img width="1920" height="1280" src="/images/owls/burrowing.jpg" alt="image of a burrowing owl" />
        </picture>
      </button>
    </li>
    <li>
      <button>
        <picture>
          <source type="image/avif" srcset="/images/owls/hawk.avif" />
          <img width="1920" height="1280" src="/images/owls/hawk.jpg" alt="image of a northern hawk-owl" />
        </picture>
      </button>
    </li>
  </ul>
</div>
.gallery-example, .gallery-selected {
  margin-bottom: 16px;
}

.gallery-example ul {
  list-style-type: none;
  display: flex;
}

All of these UI elements share one thing in common: there is this notion of items / content being either active or inactive.

The ActiveList provides a host of methods to manipulate the contents inside of the list. Ranging from insertion, removal, to moving and swapping items, but also activating and deactivating items.

The most important things to know is that the ActiveList will always keep track of the active items, no matter how you manipulate it.

If you move an active item, it will remain active. If you insert new items the old active item(s) will stay active. If you swap an item it will remain active if it is active. Etc etc

An ActiveList contains items / values. These can be whatever you want them to be, references to DOM elements, an object, strings, numbers, booleans you name it.

Each item in the ActiveList is wrapped in an ActiveListContent.

An ActiveListContent knows things like: whether it is currently active or not, whether it is the first item or the last item in the ActiveList, if there is an item next or before it.

An ActiveListContent also has methods so it can move / swap / remove / activate itself.

2. Initialization

The ActiveList can be initialized by calling the constructor. The constructor takes two arguments the config and an optional subscriber.

The config allows for the ActiveList to be tuned to the use case. In the next sections we dive deeper into what can be configured.

The second argument is an optional subscriber, the subscriber is a callback function, allowing you to observe changes of the ActiveList. When using vanilla JavaScript the callback is the place to perform any DOM manipulations. The callback receives the event that occurred so you can act on it.

When using reactive frameworks such as React, Vue, Angular or Svelte etc etc. The subscriber is not necessary since your framework of choice will do the heavy lifting of syncing the state of the ActiveList with the DOM. For more information see "Usage with Frameworks"

Initialization code example
import { ActiveList } from '@uiloos/core';

const config = {
  contents: ["a", "b", "c"],
  activeIndexes: [1]
};

function subscriber(activeList, event) {
  console.log(event);
}

const activeList = new ActiveList(config, subscriber)
import { ActiveList, ActiveListEvent } from '@uiloos/core';

const config = {
  contents: ['a', 'b', 'c'],
  activeIndexes: [1]
};

function subscriber(
  activeList: ActiveList<string>,
  event: ActiveListEvent<string>
) {
  console.log(event);
}

const activeList = new ActiveList(config, subscriber);

3. Live properties

The ActiveList tracks the status of itself in "live" properties. These live properties will sync automatically whenever you perform an action (call a method) of the ActiveList, such as removal / activation or insertion.

In other words: each time you call a method to alter the ActiveList, all "live" properties will have been updated to reflect the current status.

  1. contents which contains all ActiveListContent's currently in the ActiveList. If you ever need to loop over the entire ActiveList this is the property to loop over.
  2. activeContents, an array, which contains only the active ActiveListContent's.
  3. activeIndexes, also an array, but this time it contains only the active indexes, which are numbers.
  4. active, another array, it contains all active "values". So it basically like activeContents except it is unboxed.
  5. lastActivatedContent contains the last activated ActiveListContent. Is null if no item is activated.
  6. lastActivated contains the last activated value, is basically the same a lastActivatedContent but unboxed. Is null if no item is activated.
  7. lastActivatedIndex the last index which was activated. Is -1 if no item is activated. The lastActivatedIndex determines which ActiveListContent is considered next and previous. It also determines the direction of the ActiveList.
  8. lastDeactivatedContent contains the last deactivated ActiveListContent. Is null if no item was deactivated.
  9. lastDeactivated contains the last deactivated value, is basically the same a lastDeactivatedContent but unboxed. Is null if no item was deactivated.
  10. lastDeactivatedIndex the last index which was deactivated. Is -1 if no item was deactivated.
  11. direction is a string telling which direction the ActiveList moved to on it last activation. See Direction for more information.
  12. oppositeDirection is a string which always has opposite value of the current direction.
  13. autoPlay whether or not the AutoPlay is currently playing, and at what duration. See AutoPlay for more information.

4. Multiple or single mode

The ActiveList be configured to allow multiple items to be active the same time, a specific number of items, or only one item.

The ActiveListConfig has a property called maxActivationLimit it determines how many items can be active at the same time. By default it is set to 1 meaning that only one item can be activated at a time. When you set maxActivationLimit to 1 the ActiveList is considered to be in single mode.

When in single mode, the lastActivatedContent, lastActivated and lastActivatedIndex will always refer to the current active item.

When maxActivationLimit is set to false there is no limit to the items which an be activated.

When the maxActivationLimit is set to a specific number, it will be limited to that amount. So you could set it to 3 and allow only three items to be active at the same time.

When you set maxActivationLimit to false or a number greater than one, the ActiveList is considered to be in multiple mode.

5. Circular or linear mode

The ActiveList is by default linear, meaning that it has a start and an finish.

By setting isCircular to true the ActiveList becomes circular. When circular the next and previous will wrap around.

When the ActiveList is on the last index and next() is called it will activate the first item. When the ActiveList is on the first index and previous() is called it will activate the last item.

When isCircular is true each ActiveListContent will never have the properties isLast and isFirst set to true, because there is no start and finish.

Is circular is useful when making carousels which you want to loop over the content indefinitely.

6. Direction

The ActiveList has a property called direction it holds the direction the ActiveList moved to when an ActiveListContent is activated or deactivated.

The direction is useful for triggering different animations based on movement.

The direction can either be previous or next. Each direction is assigned a string value, by default previous is assigned "left", and next is assigned "right". You can configure the values of next and previous as you please.

The direction is based on the shortest path from the current lastActivatedIndex to the new lastActivatedIndex. This means that when the ActiveList is circular it might sometimes be quicker to go "previous" than to go "next".

If the lastActivatedIndex is -1 the direction is always considered next. The lastActivatedIndex is -1 when no content is active.

If the ActiveList is circular, and previous or next tie, the direction will become next.

7. Cooldown

Sometimes it is useful to prevent many activations / deactivations from happening in rapid succession because you want an animation to finish.

For this reason a cooldown can be configured. When a cooldown is active for a specified number of milliseconds, all other action / deactivation calls are simply ignored.

A cooldown can be configured globally (per ActiveList instance), or passed in via options to each activation / deactivation method. When both are present the cooldown from the method's options takes precedence.

A cooldown can either be a number or a callback function. Via a callback function it is possible to set a cooldown based on the ActiveListContent. This allows each content to have its own cooldown duration.

A cooldown is only checked when the action came from a end-user. This is determined by the ActiveListActivationOptions's isUserInteraction boolean. Whenever the boolean is set to false, the cooldown is ignored.

8. AutoPlay

An ActiveList can be put into AutoPlay mode, this means that it will move through the ActiveList by calling next() at a configured duration.

The AutoPlay will automatically stop when the end of the contents are reached, unless when the ActiveList has isCircular set to true, in this case it will restart from the first content. Allowing for an infinitely playing ActiveList, which can be useful in a carousel.

The duration can either be set globally (per ActiveList instance) to a specific number, or a callback function based on the ActiveListContent, meaning you can set a duration for each slide in a carousel for example.

The ActiveList can be paused via pause() and then resumed again via play(). When resumed it will take into account the duration that had already passed. For example: if the duration is 1000 milliseconds, and the user pauses after 800 milliseconds, when resumed the item will stay active for another 200 milliseconds. This is because there was 200 milliseconds remaining for the duration.

The ActiveList can also be stopped via stop(). The difference between stop() and pause(), is that when play() is called after stop() the duration is reset. For example: if the duration is 500 milliseconds, and the user stops after 250 milliseconds, when play is called, the item will stay active for 1000 milliseconds. This is because the duration is reset and not remembered.

The autoPlay can be configured to stop on any user interaction via the stopsOnUserInteraction configuration. When set to true is will stop the autoPlay, when set to false (the default) it will debounce instead. Meaning that if the duration is set to 2000 milliseconds, and the user presses "next" after 1999 milliseconds, that the next item will be active for 2000 milliseconds, and not 1 milliseconds. In effect the "duration" has been reset for the next slide.

Diving a little bit deeper into "user" interaction: each time a activation / deactivation method is called you can configure if it is a user interaction or not. By default all activation / deactivation calls have their isUserInteraction configuration set to true.

AutoPlay ignores any cooldown which might be active, as a cooldown is not considered a isUserInteraction. Meaning that if you set a cooldown duration higher than the autoPlay duration, the autoPlay will still keep playing, and ignores the cooldown.

IMPORTANT: the autoPlay cannot be started without at least one active ActiveListContent. This is because the autoPlay activates the "next" content, without any current active items there is no next item.

That autoPlay will stop if all content is removed whilst the ActiveList is playing.

9. History

The ActiveList can keep track of all events that occurred, by default is it configured not to keep any history.

When you set keepHistoryFor to a number, the ActiveList will make sure the history array will never exceed that size.

If the size is exceeded the oldest event is removed to make place for the new event. This is based on the first in first out principle.

Tutorials
Learn how to use the ActiveList