jQuery / Method / .slice() - Select an Index Range

jQuery’s .slice(start, end) returns a new jQuery object for a range of the current collection, including start but excluding end. Indices begin at zero; omit end to continue through the last element. It does not delete the other elements from the original collection or document.

Read ranges and negative indices

Indices in the .slice() API refer to the current collection, not sibling positions under an HTML parent. For Alpha, Beta, Gamma, Delta, Epsilon and Zeta, indices are 0 through 5. Negative values count from the collection’s end; -1 is the final element’s position.

Call Result among six items Reason
.slice(1, 4) Beta, Gamma, Delta Include 1, exclude 4
.slice(2) Gamma through Zeta Omitted end
.slice(-2) Epsilon, Zeta Second-last through end
.slice(1, -1) Beta through Epsilon Stop before last position
.slice(3, 3), .slice(4, 2) Empty collection No forward interval to include

end is not a count. .slice(1, 4) selects three elements at 1, 2 and 3, not four. Use .eq(index) for a single item. .filter() selects by conditions rather than a contiguous index range.

Complete example of ranges and filter order

Save all code as UTF-8 in slice-demo.html and open it in a browser. Internet is needed for the official jQuery file 4.0.0 from its content delivery network (CDN); no installation is required. Ranges, filter order, adding items, reset and Console snippets were executed with 3.7.1 and 4.0.0.

eligible is a sample class marking qualifying items. Six items are present initially, with the selected range highlighted in teal. All unselected items remain in the document.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Select a range from a collection</title>
  <script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
  <style>
    body { font: 16px/1.6 sans-serif; max-width: 760px; margin: 24px auto; padding: 16px; }
    button, select { font: inherit; margin: 4px; max-width: 100%; }
    li { border: 1px solid #aab; padding: 8px; margin: 4px; }
    .picked { background: #d9f4ef; border-color: teal; }
    pre { white-space: pre-wrap; overflow-wrap: anywhere; }
  </style>
</head>
<body>
  <h1>Select a collection range</h1>
  <label for="mode">Range:</label>
  <select id="mode">
    <option value="middle">slice(1, 4)</option>
    <option value="last">slice(-2)</option>
    <option value="inner">slice(1, -1)</option>
    <option value="from">slice(2)</option>
    <option value="filterFirst">filter('.eligible').slice(1, 3)</option>
    <option value="sliceFirst">slice(1, 3).filter('.eligible')</option>
    <option value="empty">slice(4, 2)</option>
  </select>
  <button type="button" id="add">Add Eta</button>
  <button type="button" id="reset">Reset</button>
  <ul id="items">
    <li class="eligible" data-name="Alpha">Alpha (eligible)</li>
    <li data-name="Beta">Beta</li>
    <li class="eligible" data-name="Gamma">Gamma (eligible)</li>
    <li data-name="Delta">Delta</li>
    <li class="eligible" data-name="Epsilon">Epsilon (eligible)</li>
    <li class="eligible" data-name="Zeta">Zeta (eligible)</li>
  </ul>
  <pre id="result" aria-live="polite"></pre>
  <script>
    $(function () {
      const initial = $("#items").html();
      function report() {
        const $all = $("#items > li");
        let $selected;
        switch ($("#mode").val()) {
          case "last": $selected = $all.slice(-2); break;
          case "inner": $selected = $all.slice(1, -1); break;
          case "from": $selected = $all.slice(2); break;
          case "filterFirst": $selected = $all.filter(".eligible").slice(1, 3); break;
          case "sliceFirst": $selected = $all.slice(1, 3).filter(".eligible"); break;
          case "empty": $selected = $all.slice(4, 2); break;
          default: $selected = $all.slice(1, 4);
        }
        $all.removeClass("picked");
        $selected.addClass("picked");
        const names = $selected.map(function () { return this.dataset.name; }).get();
        $("#result").text(`source=${$all.length}\nselected=${$selected.length}: ${names.join(", ") || "(none)"}\nDOM items=${$("#items > li").length}`);
      }
      $("#mode").on("change", report);
      $("#add").on("click", function () {
        if (!$("#eta").length) $("#items").append('<li id="eta" class="eligible" data-name="Eta">Eta (eligible)</li>');
        report();
      });
      $("#reset").on("click", function () { $("#items").html(initial); $("#mode").val("middle"); report(); });
      report();
    });
  </script>
</body>
</html>

Initially .slice(1, 4) selects three items. source and DOM items both stay at six.

source=6
selected=3: Beta, Gamma, Delta
DOM items=6
  1. slice(-2) highlights Epsilon and Zeta; slice(1, -1) highlights Beta, Gamma, Delta and Epsilon. Reset and change one condition at a time.
  2. filter('.eligible').slice(1, 3) first reduces to Alpha, Gamma, Epsilon and Zeta, then selects positions 1 and 2: Gamma and Epsilon.
  3. slice(1, 3).filter('.eligible') first selects Beta and Gamma from the original, then keeps Gamma only. The preceding collection changes the indices’ meaning.
  4. slice(4, 2) returns zero items without removing the six originals.
  5. With slice(-2), press Add Eta: Zeta and Eta become selected because report() selects all seven afresh. Duplicate additions are prevented.
  6. Reset restores the list and .slice(1, 4) mode.

A stored const $last = $("#items > li").slice(-2) does not automatically follow new additions. It keeps its original Epsilon and Zeta references. Select again after changes to the Document Object Model (DOM) when the current interval is needed.

Check boundaries and calculate page ranges

After Reset, run this in the developer tools Console. Oversized bounds are clamped to the available length; a start beyond the end returns empty. The last line confirms that a new jQuery collection contains references to the same DOM nodes, not clones.

const $items = $("#items > li");
const names = $set => $set.map(function () { return this.dataset.name; }).get().join(",");
console.log(`slice(1,4)=${names($items.slice(1, 4))}`);
console.log(`slice(-2)=${names($items.slice(-2))}`);
console.log(`slice(1,-1)=${names($items.slice(1, -1))}`);
console.log(`equal bounds=${$items.slice(3, 3).length}; beyond end=${$items.slice(10).length}`);
console.log(`clamped range=${$items.slice(-99, 99).length}; original=${$items.length}`);
console.log(`same node=${$items.slice(1, 2).get(0) === $items.get(1)}`);
slice(1,4)=Beta,Gamma,Delta
slice(-2)=Epsilon,Zeta
slice(1,-1)=Beta,Gamma,Delta,Epsilon
equal bounds=0; beyond end=0
clamped range=6; original=6
same node=true

For one-based page numbers and a positive integer page size, start is (page - 1) × pageSize and end is start + pageSize. This snippet selects two items for page two in the same Console. Validate first: a negative page could otherwise become a backwards index in slice.

const page = 2;
const pageSize = 2;
if (!Number.isInteger(page) || page < 1 || !Number.isInteger(pageSize) || pageSize < 1) {
  throw new RangeError("Use positive integer page and pageSize");
}
const start = (page - 1) * pageSize;
const $pageItems = $("#items > li").slice(start, start + pageSize);
console.log(`page=${page}: ${$pageItems.map(function () { return this.dataset.name; }).get().join(",")}`);
page=2: Gamma,Delta

This calculates a subset; it neither hides other items nor fetches data from a server. Real page navigation needs separate visibility, total-count and current-page management. Slicing items already loaded into a document does not itself reduce server pagination work or download volume.

Troubleshoot unexpected items

Inspect .length and the collection’s current order first. A narrower selector or preceding .filter() changes the reference collection. Do not confuse it with sibling-based CSS numbering or count indices from one. To include a desired final index, pass that index plus one as end.

slice builds a selection without cloning, moving or deleting nodes. Applying .addClass() or .text() to the result still changes the shared actual nodes. Use an explicit cloning operation if you need independent nodes. An empty jQuery object still exists and is truthy; test .length rather than the object’s Boolean value.