Repository: lynx-family/lynx-stack
Pull request #240: feat(web): list supports list-type: flow
Author: login: Sherry-hue
Labels: name: enhancement
description: New feature or request
name: platform:Web
Created: 2025-03-18T10:45:55Z | Merged: 2025-03-19T12:17:37Z

## Summary

feat: The list element supports list-type with **flow**.

It supports all attributes and events under single, and also provides `full-span`.

For detailed usage, please refer to the official website.

## Checklist

- [x] Tests updated (or not required).
- [x] Documentation updated (or not required).



Diff:
diff --git a/.changeset/modern-papayas-boil.md b/.changeset/modern-papayas-boil.md
new file mode 100644
index 0000000000..dfe4d35d0e
--- /dev/null
+++ b/.changeset/modern-papayas-boil.md
@@ -0,0 +1,9 @@
+---
+"@lynx-js/web-elements": minor
+---
+
+feat(web): The list element supports list-type with **flow**.
+
+It supports all attributes and events under single, and also provides `full-span`.
+
+For detailed usage, please refer to the official website.
diff --git a/packages/web-platform/web-elements/src/XList/XListAttributes.ts b/packages/web-platform/web-elements/src/XList/XListAttributes.ts
index fa86992a6e..8d91ce96f5 100644
--- a/packages/web-platform/web-elements/src/XList/XListAttributes.ts
+++ b/packages/web-platform/web-elements/src/XList/XListAttributes.ts
@@ -17,6 +17,8 @@ export class XListAttributes
   static observedAttributes = [
     'sticky-offset',
     'initial-scroll-index',
+    'span-count',
+    'column-count',
   ];
 
   #dom: XList;
@@ -28,6 +30,14 @@ export class XListAttributes
     (v) => `${parseFloat(v)}px`,
   );
 
+  @registerAttributeHandler('span-count', true)
+  @registerAttributeHandler('column-count', true)
+  #handlerCount = bindToStyle(
+    () => this.#dom,
+    '--list-item-span-count',
+    (v) => `${parseFloat(v)}`,
+  );
+
   constructor(dom: XList) {
     this.#dom = dom;
   }
diff --git a/packages/web-platform/web-elements/src/XList/x-list.css b/packages/web-platform/web-elements/src/XList/x-list.css
index a879d4d7a7..b9a024ee1a 100644
--- a/packages/web-platform/web-elements/src/XList/x-list.css
+++ b/packages/web-platform/web-elements/src/XList/x-list.css
@@ -7,6 +7,7 @@ x-list {
   contain: layout;
   scrollbar-width: none;
   --list-item-sticky-offset: 0;
+  --list-item-span-count: 0;
 }
 
 x-list > *:not(list-item) {
@@ -60,25 +61,21 @@ x-list > list-item, x-list > lynx-wrapper > list-item {
   display: flex;
 }
 
-x-list[list-type="single"] {
-  display: flex;
-  flex-direction: column;
-  align-items: stretch;
+x-list {
   overflow-y: scroll !important;
   overflow-x: clip !important;
 }
 
-x-list[list-type="single"][scroll-orientation="horizontal"] {
-  flex-direction: row;
+x-list[scroll-orientation="horizontal"] {
   overflow-x: scroll !important;
   overflow-y: clip !important;
 }
 
-x-list[list-type="single"][enable-scroll="false"] {
+x-list[enable-scroll="false"] {
   overflow-y: hidden !important;
 }
 
-x-list[list-type="single"][scroll-orientation="horizontal"][enable-scroll="false"] {
+x-list[scroll-orientation="horizontal"][enable-scroll="false"] {
   overflow-x: hidden !important;
 }
 
@@ -87,47 +84,40 @@ list-item[sticky-top], list-item[sticky-bottom] {
   z-index: 1;
 }
 
-x-list[list-type="single"] > list-item[sticky-top],
-x-list[list-type="single"] > lynx-wrapper > list-item[sticky-top] {
+x-list > list-item[sticky-top], x-list > lynx-wrapper > list-item[sticky-top] {
   top: var(--list-item-sticky-offset);
 }
 
-x-list[list-type="single"] > list-item[sticky-bottom],
-x-list[list-type="single"] > lynx-wrapper > list-item[sticky-bottom] {
+x-list > list-item[sticky-bottom],
+x-list > lynx-wrapper > list-item[sticky-bottom] {
   bottom: var(--list-item-sticky-offset);
 }
 
-x-list[list-type="single"][scroll-orientation="horizontal"]
-  > list-item[sticky-top],
-x-list[list-type="single"][scroll-orientation="horizontal"]
-  > lynx-wrapper
-  > list-item[sticky-top] {
+x-list[scroll-orientation="horizontal"] > list-item[sticky-top],
+x-list[scroll-orientation="horizontal"] > lynx-wrapper > list-item[sticky-top] {
   top: unset;
   left: var(--list-item-sticky-offset);
 }
 
-x-list[list-type="single"][scroll-orientation="horizontal"]
-  > list-item[sticky-bottom],
-x-list[list-type="single"][scroll-orientation="horizontal"]
+x-list[scroll-orientation="horizontal"] > list-item[sticky-bottom],
+x-list[scroll-orientation="horizontal"]
   > lynx-wrapper
   > list-item[sticky-bottom] {
   bottom: unset;
   right: var(--list-item-sticky-offset);
 }
 
-x-list[list-type="single"][item-snap],
-x-list[list-type="single"][paging-enabled] {
+x-list[item-snap], x-list[paging-enabled] {
   scroll-snap-type: y mandatory;
   scroll-snap-stop: always;
 }
 
-x-list[list-type="single"][item-snap][scroll-orientation="horizontal"],
-x-list[list-type="single"][paging-enabled][scroll-orientation="horizontal"] {
+x-list[item-snap][scroll-orientation="horizontal"],
+x-list[paging-enabled][scroll-orientation="horizontal"] {
   scroll-snap-type: x mandatory;
 }
 
-x-list[list-type="single"][item-snap] > list-item,
-x-list[list-type="single"][item-snap] > lynx-wrapper > list-item {
+x-list[item-snap] > list-item, x-list[item-snap] > lynx-wrapper > list-item {
   scroll-snap-align: start;
 }
 
@@ -145,3 +135,42 @@ x-list::part(lower-threshold-observer) {
 x-list[vertical-orientation="false"]::part(lower-threshold-observer) {
   flex-direction: row-reverse;
 }
+
+/* list-type single */
+x-list[list-type="single"] {
+  display: flex;
+  flex-direction: column;
+  align-items: stretch;
+}
+
+x-list[list-type="single"][scroll-orientation="horizontal"] {
+  flex-direction: row;
+}
+
+/* list-type flow */
+x-list[list-type="flow"]::part(content) {
+  display: grid;
+  grid-template-columns: repeat(var(--list-item-span-count), 1fr);
+  grid-auto-rows: min-content;
+  justify-items: stretch;
+  align-items: start;
+}
+
+x-list[list-type="flow"][scroll-orientation="horizontal"]::part(content) {
+  grid-template-rows: repeat(var(--list-item-span-count), 1fr);
+  grid-auto-flow: column;
+  grid-auto-columns: min-content;
+  justify-items: start;
+  align-items: stretch;
+}
+
+x-list[list-type="flow"] list-item[full-span]:not([full-span="false"]) {
+  grid-column-start: 1;
+  grid-column-end: calc(var(--list-item-span-count) + 1);
+}
+
+x-list[list-type="flow"][scroll-orientation="horizontal"]
+  list-item[full-span]:not([full-span="false"]) {
+  grid-row-start: 1;
+  grid-row-end: calc(var(--list-item-span-count) + 1);
+}
diff --git a/packages/web-platform/web-tests/tests/web-elements.spec.ts b/packages/web-platform/web-tests/tests/web-elements.spec.ts
index bb8dabf2db..1b62648473 100644
--- a/packages/web-platform/web-tests/tests/web-elements.spec.ts
+++ b/packages/web-platform/web-tests/tests/web-elements.spec.ts
@@ -2024,6 +2024,40 @@ test.describe('web-elements test suite', () => {
         ).toBeTruthy();
       },
     );
+
+    test('basic-flow', async ({ page, browserName }, { titlePath }) => {
+      const title = getTitle(titlePath);
+      await gotoWebComponentPage(page, title);
+      await diffScreenShot(page, title, 'initial');
+      if (browserName === 'webkit') test.skip(); // cannot wheel
+      await page.mouse.move(100, 100);
+      await page.mouse.wheel(300, 0);
+      await diffScreenShot(page, title, 'wheel-x-not-wheelable');
+      await page.mouse.wheel(0, 300);
+      await diffScreenShot(page, title, 'wheel-y-wheelable');
+    });
+    test(
+      'scroll-orientation-flow',
+      async ({ page }, { titlePath }) => {
+        const title = getTitle(titlePath);
+        await gotoWebComponentPage(page, title);
+        await diffScreenShot(page, title, 'index');
+      },
+    );
+    test('sticky-flow', async ({ page, browserName }, { titlePath }) => {
+      const title = getTitle(titlePath);
+      await gotoWebComponentPage(page, title);
+      await diffScreenShot(page, title, 'index');
+      if (browserName === 'webkit') test.skip(); // cannot wheel
+      await page.mouse.move(200, 300);
+      await page.mouse.wheel(0, 500);
+      await diffScreenShot(page, title, 'sticky-y-scroll');
+    });
+    test('full-span', async ({ page, browserName }, { titlePath }) => {
+      const title = getTitle(titlePath);
+      await gotoWebComponentPage(page, title);
+      await diffScreenShot(page, title, 'index');
+    });
   });
   test.describe('x-input', () => {
     test('placeholder', async ({ page }, { titlePath }) => {
diff --git a/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/basic-flow/initial-chromium-linux.png b/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/basic-flow/initial-chromium-linux.png
new file mode 100644
index 0000000000..26440dc4ea
Binary files /dev/null and b/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/basic-flow/initial-chromium-linux.png differ
diff --git a/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/basic-flow/initial-firefox-linux.png b/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/basic-flow/initial-firefox-linux.png
new file mode 100644
index 0000000000..5319c3562e
Binary files /dev/null and b/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/basic-flow/initial-firefox-linux.png differ
diff --git a/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/basic-flow/initial-webkit-linux.png b/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/basic-flow/initial-webkit-linux.png
new file mode 100644
index 0000000000..c9054a11d2
Binary files /dev/null and b/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/basic-flow/initial-webkit-linux.png differ
diff --git a/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/basic-flow/wheel-x-not-wheelable-chromium-linux.png b/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/basic-flow/wheel-x-not-wheelable-chromium-linux.png
new file mode 100644
index 0000000000..26440dc4ea
Binary files /dev/null and b/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/basic-flow/wheel-x-not-wheelable-chromium-linux.png differ
diff --git a/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/basic-flow/wheel-x-not-wheelable-firefox-linux.png b/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/basic-flow/wheel-x-not-wheelable-firefox-linux.png
new file mode 100644
index 0000000000..5319c3562e
Binary files /dev/null and b/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/basic-flow/wheel-x-not-wheelable-firefox-linux.png differ
diff --git a/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/basic-flow/wheel-y-wheelable-chromium-linux.png b/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/basic-flow/wheel-y-wheelable-chromium-linux.png
new file mode 100644
index 0000000000..1e56463709
Binary files /dev/null and b/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/basic-flow/wheel-y-wheelable-chromium-linux.png differ
diff --git a/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/basic-flow/wheel-y-wheelable-firefox-linux.png b/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/basic-flow/wheel-y-wheelable-firefox-linux.png
new file mode 100644
index 0000000000..00c8d0191d
Binary files /dev/null and b/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/basic-flow/wheel-y-wheelable-firefox-linux.png differ
diff --git a/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/full-span/index-chromium-linux.png b/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/full-span/index-chromium-linux.png
new file mode 100644
index 0000000000..3e3882cfed
Binary files /dev/null and b/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/full-span/index-chromium-linux.png differ
diff --git a/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/full-span/index-firefox-linux.png b/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/full-span/index-firefox-linux.png
new file mode 100644
index 0000000000..b19f183fad
Binary files /dev/null and b/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/full-span/index-firefox-linux.png differ
diff --git a/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/full-span/index-webkit-linux.png b/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/full-span/index-webkit-linux.png
new file mode 100644
index 0000000000..0d6616f8fe
Binary files /dev/null and b/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/full-span/index-webkit-linux.png differ
diff --git a/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/scroll-orientation-flow/index-chromium-linux.png b/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/scroll-orientation-flow/index-chromium-linux.png
new file mode 100644
index 0000000000..932ba764a7
Binary files /dev/null and b/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/scroll-orientation-flow/index-chromium-linux.png differ
diff --git a/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/scroll-orientation-flow/index-firefox-linux.png b/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/scroll-orientation-flow/index-firefox-linux.png
new file mode 100644
index 0000000000..6b7b1f2770
Binary files /dev/null and b/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/scroll-orientation-flow/index-firefox-linux.png differ
diff --git a/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/scroll-orientation-flow/index-webkit-linux.png b/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/scroll-orientation-flow/index-webkit-linux.png
new file mode 100644
index 0000000000..8107b19500
Binary files /dev/null and b/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/scroll-orientation-flow/index-webkit-linux.png differ
diff --git a/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/sticky-flow/index-chromium-linux.png b/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/sticky-flow/index-chromium-linux.png
new file mode 100644
index 0000000000..07b5c1d3c4
Binary files /dev/null and b/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/sticky-flow/index-chromium-linux.png differ
diff --git a/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/sticky-flow/index-firefox-linux.png b/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/sticky-flow/index-firefox-linux.png
new file mode 100644
index 0000000000..3cc424406f
Binary files /dev/null and b/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/sticky-flow/index-firefox-linux.png differ
diff --git a/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/sticky-flow/index-webkit-linux.png b/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/sticky-flow/index-webkit-linux.png
new file mode 100644
index 0000000000..fb4039fea5
Binary files /dev/null and b/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/sticky-flow/index-webkit-linux.png differ
diff --git a/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/sticky-flow/sticky-y-scroll-chromium-linux.png b/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/sticky-flow/sticky-y-scroll-chromium-linux.png
new file mode 100644
index 0000000000..39605522ba
Binary files /dev/null and b/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/sticky-flow/sticky-y-scroll-chromium-linux.png differ
diff --git a/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/sticky-flow/sticky-y-scroll-firefox-linux.png b/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/sticky-flow/sticky-y-scroll-firefox-linux.png
new file mode 100644
index 0000000000..52ab738c00
Binary files /dev/null and b/packages/web-platform/web-tests/tests/web-elements.spec.ts-snapshots/x-list/sticky-flow/sticky-y-scroll-firefox-linux.png differ
diff --git a/packages/web-platform/web-tests/tests/web-elements/x-list/basic-flow.html b/packages/web-platform/web-tests/tests/web-elements/x-list/basic-flow.html
new file mode 100644
index 0000000000..5575832f35
--- /dev/null
+++ b/packages/web-platform/web-tests/tests/web-elements/x-list/basic-flow.html
@@ -0,0 +1,100 @@
+<!DOCTYPE html>
+<!-- Copyright 2024 The Lynx Authors. All rights reserved.
+ Licensed under the Apache License Version 2.0 that can be found in the
+ LICENSE file in the root directory of this source tree. -->
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>web playground</title>
+    <meta content="yes" name="apple-mobile-web-app-capable">
+    <meta content="default" name="apple-mobile-web-app-status-bar-style">
+    <meta content="telephone=no" name="format-detection">
+    <meta content="portrait" name="screen-orientation">
+    <meta
+      content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no"
+      name="viewport"
+    >
+    <meta content="portrait" name="x5-orientation">
+    <link
+      href="/node_modules/@lynx-js/web-elements/index.css"
+      rel="stylesheet"
+    />
+    <link
+      href="/web-elements.css"
+      rel="stylesheet"
+    />
+
+    <style>
+    @import url("../../common.css");
+    x-list {
+      width: 100%;
+      height: 500px;
+    }
+
+    .item {
+      border-width: 5px;
+      border-color: green;
+      width: 100%;
+      height: 100%;
+      background-color: yellow;
+      margin-bottom: 10px;
+    }
+
+    .left {
+      height: 80px;
+    }
+
+    .right {
+      height: 100px;
+    }
+    </style>
+  </head>
+
+  <body>
+    <script src="/web-elements.js" defer></script>
+    <x-view class="page" style="flex-direction: column;">
+      <x-list list-type="flow" span-count="2">
+        <list-item class="left" item-key="1" id="1"><x-view class="item"
+          >1</x-view></list-item>
+        <list-item class="right" item-key="2" id="2"><x-view class="item"
+          >2</x-view></list-item>
+        <list-item class="left" item-key="3" id="3"><x-view class="item"
+          >3</x-view></list-item>
+        <list-item class="right" item-key="4" id="4"><x-view class="item"
+          >4</x-view></list-item>
+        <list-item class="left" item-key="5" id="5"><x-view class="item"
+          >5</x-view></list-item>
+        <list-item class="right" item-key="6" id="6"><x-view class="item"
+          >6</x-view></list-item>
+        <list-item class="left" item-key="7" id="7"><x-view class="item"
+          >7</x-view></list-item>
+        <list-item class="right" item-key="8" id="8"><x-view class="item"
+          >8</x-view></list-item>
+        <list-item class="left" item-key="9" id="9"><x-view class="item"
+          >9</x-view></list-item>
+        <list-item class="right" item-key="10" id="10"><x-view class="item"
+          >10</x-view></list-item>
+        <list-item class="left" item-key="11" id="11"><x-view class="item"
+          >11</x-view></list-item>
+        <list-item class="right" item-key="12" id="12"><x-view class="item"
+          >12</x-view></list-item>
+        <list-item class="left" item-key="13" id="13"><x-view class="item"
+          >13</x-view></list-item>
+        <list-item class="right" item-key="14" id="14"><x-view class="item"
+          >14</x-view></list-item>
+        <list-item class="left" item-key="15" id="15"><x-view class="item"
+          >15</x-view></list-item>
+        <list-item class="right" item-key="16" id="16"><x-view class="item"
+          >16</x-view></list-item>
+        <list-item class="left" item-key="17" id="17"><x-view class="item"
+          >17</x-view></list-item>
+        <list-item class="right" item-key="18" id="18"><x-view class="item"
+          >18</x-view></list-item>
+        <list-item class="left" item-key="19" id="19"><x-view class="item"
+          >19</x-view></list-item>
+        <list-item class="right" item-key="20" id="20"><x-view class="item"
+          >20</x-view></list-item>
+      </x-list>
+    </x-view>
+  </body>
+</html>
diff --git a/packages/web-platform/web-tests/tests/web-elements/x-list/full-span.html b/packages/web-platform/web-tests/tests/web-elements/x-list/full-span.html
new file mode 100644
index 0000000000..28de4cdecb
--- /dev/null
+++ b/packages/web-platform/web-tests/tests/web-elements/x-list/full-span.html
@@ -0,0 +1,168 @@
+<!DOCTYPE html>
+<!-- Copyright 2024 The Lynx Authors. All rights reserved.
+ Licensed under the Apache License Version 2.0 that can be found in the
+ LICENSE file in the root directory of this source tree. -->
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>web playground</title>
+    <meta content="yes" name="apple-mobile-web-app-capable">
+    <meta content="default" name="apple-mobile-web-app-status-bar-style">
+    <meta content="telephone=no" name="format-detection">
+    <meta content="portrait" name="screen-orientation">
+    <meta
+      content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no"
+      name="viewport"
+    >
+    <meta content="portrait" name="x5-orientation">
+    <link
+      href="/node_modules/@lynx-js/web-elements/index.css"
+      rel="stylesheet"
+    />
+    <link
+      href="/web-elements.css"
+      rel="stylesheet"
+    />
+
+    <style>
+    @import url("../../common.css");
+    x-list {
+      width: 100%;
+      height: 500px;
+    }
+
+    .item {
+      border-width: 5px;
+      border-color: green;
+      width: 100%;
+      height: 100%;
+      background-color: yellow;
+      margin-bottom: 10px;
+    }
+
+    #vertical {
+      .left {
+        height: 80px;
+      }
+
+      .right {
+        height: 100px;
+      }
+    }
+
+    #horizontal {
+      .left {
+        width: 300px;
+      }
+
+      .right {
+        width: 500px;
+      }
+    }
+    </style>
+  </head>
+
+  <body>
+    <script src="/web-elements.js" defer></script>
+    <x-view class="page" style="flex-direction: column;">
+      <x-list list-type="flow" span-count="2" id="vertical">
+        <list-item
+          class="left"
+          item-key="1"
+          id="1"
+          full-span
+        ><x-view class="item">1</x-view></list-item>
+        <list-item class="right" item-key="2" id="2"><x-view class="item"
+          >2</x-view></list-item>
+        <list-item class="left" item-key="3" id="3"><x-view class="item"
+          >3</x-view></list-item>
+        <list-item class="right" item-key="4" id="4"><x-view class="item"
+          >4</x-view></list-item>
+        <list-item class="left" item-key="5" id="5"><x-view class="item"
+          >5</x-view></list-item>
+        <list-item class="right" item-key="6" id="6"><x-view class="item"
+          >6</x-view></list-item>
+        <list-item class="left" item-key="7" id="7"><x-view class="item"
+          >7</x-view></list-item>
+        <list-item class="right" item-key="8" id="8"><x-view class="item"
+          >8</x-view></list-item>
+        <list-item class="left" item-key="9" id="9"><x-view class="item"
+          >9</x-view></list-item>
+        <list-item class="right" item-key="10" id="10"><x-view class="item"
+          >10</x-view></list-item>
+        <list-item class="left" item-key="11" id="11"><x-view class="item"
+          >11</x-view></list-item>
+        <list-item class="right" item-key="12" id="12"><x-view class="item"
+          >12</x-view></list-item>
+        <list-item class="left" item-key="13" id="13"><x-view class="item"
+          >13</x-view></list-item>
+        <list-item class="right" item-key="14" id="14"><x-view class="item"
+          >14</x-view></list-item>
+        <list-item class="left" item-key="15" id="15"><x-view class="item"
+          >15</x-view></list-item>
+        <list-item class="right" item-key="16" id="16"><x-view class="item"
+          >16</x-view></list-item>
+        <list-item class="left" item-key="17" id="17"><x-view class="item"
+          >17</x-view></list-item>
+        <list-item class="right" item-key="18" id="18"><x-view class="item"
+          >18</x-view></list-item>
+        <list-item class="left" item-key="19" id="19"><x-view class="item"
+          >19</x-view></list-item>
+        <list-item class="right" item-key="20" id="20"><x-view class="item"
+          >20</x-view></list-item>
+      </x-list>
+
+      <x-list
+        list-type="flow"
+        span-count="2"
+        id="horizontal"
+        scroll-orientation="horizontal"
+      >
+        <list-item
+          class="left"
+          item-key="1"
+          id="1"
+          full-span
+        ><x-view class="item">1</x-view></list-item>
+        <list-item class="right" item-key="2" id="2"><x-view class="item"
+          >2</x-view></list-item>
+        <list-item class="left" item-key="3" id="3"><x-view class="item"
+          >3</x-view></list-item>
+        <list-item class="right" item-key="4" id="4"><x-view class="item"
+          >4</x-view></list-item>
+        <list-item class="left" item-key="5" id="5"><x-view class="item"
+          >5</x-view></list-item>
+        <list-item class="right" item-key="6" id="6"><x-view class="item"
+          >6</x-view></list-item>
+        <list-item class="left" item-key="7" id="7"><x-view class="item"
+          >7</x-view></list-item>
+        <list-item class="right" item-key="8" id="8"><x-view class="item"
+          >8</x-view></list-item>
+        <list-item class="left" item-key="9" id="9"><x-view class="item"
+          >9</x-view></list-item>
+        <list-item class="right" item-key="10" id="10"><x-view class="item"
+          >10</x-view></list-item>
+        <list-item class="left" item-key="11" id="11"><x-view class="item"
+          >11</x-view></list-item>
+        <list-item class="right" item-key="12" id="12"><x-view class="item"
+          >12</x-view></list-item>
+        <list-item class="left" item-key="13" id="13"><x-view class="item"
+          >13</x-view></list-item>
+        <list-item class="right" item-key="14" id="14"><x-view class="item"
+          >14</x-view></list-item>
+        <list-item class="left" item-key="15" id="15"><x-view class="item"
+          >15</x-view></list-item>
+        <list-item class="right" item-key="16" id="16"><x-view class="item"
+          >16</x-view></list-item>
+        <list-item class="left" item-key="17" id="17"><x-view class="item"
+          >17</x-view></list-item>
+        <list-item class="right" item-key="18" id="18"><x-view class="item"
+          >18</x-view></list-item>
+        <list-item class="left" item-key="19" id="19"><x-view class="item"
+          >19</x-view></list-item>
+        <list-item class="right" item-key="20" id="20"><x-view class="item"
+          >20</x-view></list-item>
+      </x-list>
+    </x-view>
+  </body>
+</html>
diff --git a/packages/web-platform/web-tests/tests/web-elements/x-list/scroll-orientation-flow.html b/packages/web-platform/web-tests/tests/web-elements/x-list/scroll-orientation-flow.html
new file mode 100644
index 0000000000..921d8e5a5a
--- /dev/null
+++ b/packages/web-platform/web-tests/tests/web-elements/x-list/scroll-orientation-flow.html
@@ -0,0 +1,100 @@
+<!DOCTYPE html>
+<!-- Copyright 2024 The Lynx Authors. All rights reserved.
+ Licensed under the Apache License Version 2.0 that can be found in the
+ LICENSE file in the root directory of this source tree. -->
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>web playground</title>
+    <meta content="yes" name="apple-mobile-web-app-capable">
+    <meta content="default" name="apple-mobile-web-app-status-bar-style">
+    <meta content="telephone=no" name="format-detection">
+    <meta content="portrait" name="screen-orientation">
+    <meta
+      content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no"
+      name="viewport"
+    >
+    <meta content="portrait" name="x5-orientation">
+    <link
+      href="/node_modules/@lynx-js/web-elements/index.css"
+      rel="stylesheet"
+    />
+    <link
+      href="/web-elements.css"
+      rel="stylesheet"
+    />
+
+    <style>
+    @import url("../../common.css");
+    x-list {
+      width: 100%;
+      height: 500px;
+    }
+
+    .item {
+      border-width: 5px;
+      border-color: green;
+      width: 100%;
+      height: 100%;
+      background-color: yellow;
+      margin-bottom: 10px;
+    }
+
+    .left {
+      width: 300px;
+    }
+
+    .right {
+      width: 500px;
+    }
+    </style>
+  </head>
+
+  <body>
+    <script src="/web-elements.js" defer></script>
+    <x-view class="page" style="flex-direction: column;">
+      <x-list list-type="flow" span-count="2" scroll-orientation="horizontal">
+        <list-item class="left" item-key="1" id="1"><x-view class="item"
+          >1</x-view></list-item>
+        <list-item class="right" item-key="2" id="2"><x-view class="item"
+          >2</x-view></list-item>
+        <list-item class="left" item-key="3" id="3"><x-view class="item"
+          >3</x-view></list-item>
+        <list-item class="right" item-key="4" id="4"><x-view class="item"
+          >4</x-view></list-item>
+        <list-item class="left" item-key="5" id="5"><x-view class="item"
+          >5</x-view></list-item>
+        <list-item class="right" item-key="6" id="6"><x-view class="item"
+          >6</x-view></list-item>
+        <list-item class="left" item-key="7" id="7"><x-view class="item"
+          >7</x-view></list-item>
+        <list-item class="right" item-key="8" id="8"><x-view class="item"
+          >8</x-view></list-item>
+        <list-item class="left" item-key="9" id="9"><x-view class="item"
+          >9</x-view></list-item>
+        <list-item class="right" item-key="10" id="10"><x-view class="item"
+          >10</x-view></list-item>
+        <list-item class="left" item-key="11" id="11"><x-view class="item"
+          >11</x-view></list-item>
+        <list-item class="right" item-key="12" id="12"><x-view class="item"
+          >12</x-view></list-item>
+        <list-item class="left" item-key="13" id="13"><x-view class="item"
+          >13</x-view></list-item>
+        <list-item class="right" item-key="14" id="14"><x-view class="item"
+          >14</x-view></list-item>
+        <list-item class="left" item-key="15" id="15"><x-view class="item"
+          >15</x-view></list-item>
+        <list-item class="right" item-key="16" id="16"><x-view class="item"
+          >16</x-view></list-item>
+        <list-item class="left" item-key="17" id="17"><x-view class="item"
+          >17</x-view></list-item>
+        <list-item class="right" item-key="18" id="18"><x-view class="item"
+          >18</x-view></list-item>
+        <list-item class="left" item-key="19" id="19"><x-view class="item"
+          >19</x-view></list-item>
+        <list-item class="right" item-key="20" id="20"><x-view class="item"
+          >20</x-view></list-item>
+      </x-list>
+    </x-view>
+  </body>
+</html>
diff --git a/packages/web-platform/web-tests/tests/web-elements/x-list/sticky-flow.html b/packages/web-platform/web-tests/tests/web-elements/x-list/sticky-flow.html
new file mode 100644
index 0000000000..3846eab443
--- /dev/null
+++ b/packages/web-platform/web-tests/tests/web-elements/x-list/sticky-flow.html
@@ -0,0 +1,105 @@
+<!DOCTYPE html>
+<!-- Copyright 2024 The Lynx Authors. All rights reserved.
+ Licensed under the Apache License Version 2.0 that can be found in the
+ LICENSE file in the root directory of this source tree. -->
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>web playground</title>
+    <meta content="yes" name="apple-mobile-web-app-capable">
+    <meta content="default" name="apple-mobile-web-app-status-bar-style">
+    <meta content="telephone=no" name="format-detection">
+    <meta content="portrait" name="screen-orientation">
+    <meta
+      content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no"
+      name="viewport"
+    >
+    <meta content="portrait" name="x5-orientation">
+    <link
+      href="/node_modules/@lynx-js/web-elements/index.css"
+      rel="stylesheet"
+    />
+    <link
+      href="/web-elements.css"
+      rel="stylesheet"
+    />
+
+    <style>
+    @import url("../../common.css");
+    x-list {
+      width: 100%;
+      height: 500px;
+    }
+
+    .item {
+      border-width: 5px;
+      border-color: green;
+      width: 100%;
+      height: 100%;
+      background-color: yellow;
+      margin-bottom: 10px;
+    }
+
+    .left {
+      height: 80px;
+    }
+
+    .right {
+      height: 100px;
+    }
+    </style>
+  </head>
+
+  <body>
+    <script src="/web-elements.js" defer></script>
+    <x-view class="page" style="flex-direction: column;">
+      <x-list list-type="flow" span-count="2">
+        <list-item
+          class="left"
+          item-key="1"
+          id="1"
+          sticky-top
+        ><x-view class="item">1</x-view></list-item>
+        <list-item class="right" item-key="2" id="2"><x-view class="item"
+          >2</x-view></list-item>
+        <list-item class="left" item-key="3" id="3"><x-view class="item"
+          >3</x-view></list-item>
+        <list-item class="right" item-key="4" id="4"><x-view class="item"
+          >4</x-view></list-item>
+        <list-item class="left" item-key="5" id="5"><x-view class="item"
+          >5</x-view></list-item>
+        <list-item class="right" item-key="6" id="6"><x-view class="item"
+          >6</x-view></list-item>
+        <list-item class="left" item-key="7" id="7"><x-view class="item"
+          >7</x-view></list-item>
+        <list-item class="right" item-key="8" id="8"><x-view class="item"
+          >8</x-view></list-item>
+        <list-item class="left" item-key="9" id="9"><x-view class="item"
+          >9</x-view></list-item>
+        <list-item class="right" item-key="10" id="10"><x-view class="item"
+          >10</x-view></list-item>
+        <list-item class="left" item-key="11" id="11"><x-view class="item"
+          >11</x-view></list-item>
+        <list-item class="right" item-key="12" id="12"><x-view class="item"
+          >12</x-view></list-item>
+        <list-item class="left" item-key="13" id="13"><x-view class="item"
+          >13</x-view></list-item>
+        <list-item class="right" item-key="14" id="14"><x-view class="item"
+          >14</x-view></list-item>
+        <list-item class="left" item-key="15" id="15"><x-view class="item"
+          >15</x-view></list-item>
+        <list-item class="right" item-key="16" id="16"><x-view class="item"
+          >16</x-view></list-item>
+        <list-item class="left" item-key="17" id="17"><x-view class="item"
+          >17</x-view></list-item>
+        <list-item class="right" item-key="18" id="18"><x-view class="item"
+          >18</x-view></list-item>
+        <list-item class="left" item-key="19" id="19"><x-view class="item"
+          >19</x-view></list-item>
+        <list-item class="right" item-key="20" id="20" sticky-bottom><x-view
+            class="item"
+          >20</x-view></list-item>
+      </x-list>
+    </x-view>
+  </body>
+</html>


Reviews:
user: login: PupilTong
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-03-19T11:42:36Z
user: login: Sherry-hue
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-19T11:50:09Z

Review comments:
diff_hunk: @@ -28,6 +30,14 @@ export class XListAttributes
     (v) => `${parseFloat(v)}px`,
   );
 
+  @registerAttributeHandler('span-count', true)
+  @registerAttributeHandler('column-count', true)
+  #handlerCount = bindToStyle(
+    () => this.#dom,
+    '--list-item-span-count',
+    (v) => `${parseFloat(v)}`,
path: packages/web-platform/web-elements/src/XList/XListAttributes.ts
user: login: PupilTong
body: Could we detect browser compatibility and use https://developer.mozilla.org/en-US/docs/Web/CSS/attr ?
created_at: 2025-03-19T11:41:57Z
author_association: COLLABORATOR
diff_hunk: @@ -28,6 +30,14 @@ export class XListAttributes
     (v) => `${parseFloat(v)}px`,
   );
 
+  @registerAttributeHandler('span-count', true)
+  @registerAttributeHandler('column-count', true)
+  #handlerCount = bindToStyle(
+    () => this.#dom,
+    '--list-item-span-count',
+    (v) => `${parseFloat(v)}`,
path: packages/web-platform/web-elements/src/XList/XListAttributes.ts
user: login: Sherry-hue
body: If necessary, a new PR will be created to solve it, because there are other places using var
created_at: 2025-03-19T11:50:09Z
author_association: COLLABORATOR

PR comments:
user: login: changeset-bot[bot]
created_at: 2025-03-18T10:45:58Z
body: ###  🦋  Changeset detected

Latest commit: f9062c5ea328a818602dbdae55bd877ababef3e9

**The changes in this PR will be included in the next version bump.**

<details><summary>This PR includes changesets to release 1 package</summary>

  | Name                  | Type  |
| --------------------- | ----- |
| @lynx-js/web-elements | Minor |

</details>

Not sure what this means? [Click here  to learn what changesets are](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md).

[Click here if you're a maintainer who wants to add another changeset to this PR](https://github.com/Sherry-hue/lynx-stack/new/feat/list-listType-flow?filename=.changeset/healthy-feet-pay.md&value=---%0A%22%40lynx-js%2Fweb-elements%22%3A%20patch%0A%22%40lynx-js%2Fweb-tests%22%3A%20patch%0A---%0A%0Afeat(web)%3A%20list%20supports%20list-type%3A%20flow%0A)


author_association: NONE
user: login: codecov[bot]
created_at: 2025-03-18T10:52:07Z
body: ## [Codecov](https://app.codecov.io/gh/lynx-family/lynx-stack/pull/240?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lynx-family) Report
All modified and coverable lines are covered by tests :white_check_mark:

:white_check_mark: All tests successful. No failed tests found.

:loudspeaker: Thoughts on this report? [Let us know!](https://github.com/codecov/feedback/issues/255)
author_association: NONE