Data Agent
A Data Agent offers utility and cross-layer behaviors through its data-agent
attribute, providing additive enhancements at any layer (L1–L5) without claiming block-level ownership or lifecycle control. Agents can handle tasks like animations, lazy loading, or analytics, leaving state management and the block sovereignty to an Observer, if one is present.
Why Use an Agent?
Copy link to this section- Cross-Layer Flexibility
- Attach a behavior at any layer—system (L1), local context (L2), block (L3), or tail (L5).
- Example:
data-agent="Analytics"
on<body>
for global tracking, ordata-agent="LazyLoad"
on a tail element.
- Plug-and-Play
- Agents typically contain a self-contained feature—like a fade-in effect or analytics snippet—that can be quickly applied or removed.
- No Lifecycle Collisions
- Agents do not manage block lifecycle or states, so they never conflict with Observers.
Marker Reference
Copy link to this section
<!-- Basic usage -->
<div class="-content"
data-agent="LazyLoad">
<!-- The LazyLoad agent handles lazy loading of images or content -->
</div>
- Syntax:
data-agent="AgentName"
- AgentName: A descriptive identifier for the behavior (e.g.,
RevealAnimation
,InfiniteScroll
,LazyLoad
).
Purpose & Boundaries
Copy link to this sectionPurpose
Copy link to this section- Standardized Behaviors: Provide a uniform approach for common tasks like animations, logging, or data loading.
- Utility Layer: Agents can be dropped in to handle cross-layer or traditional repeated behaviors without rewriting the block’s main logic.
- Framework Independence: Because Agents lack block ownership, they easily integrate external libraries or utility scripts.
Boundaries
Copy link to this section- No Sovereignty
- Agents never manage or override a block’s lifecycle, states, or resource usage—that’s the Observer’s job.
- Valid on All Layers
- System (L1,
matrix--shop
) - Local Context (L2,
context--catalog
) - Block (L3,
product_card
) - Mutation (L4,
--featured
) — Agents may respond visually, but do not define states - Tail (L5,
-content
)
- System (L1,
Coexists with Observers
- Agents never override an Observer’s ownership of the block.
- Example (invalid): An agent tries to “take over” block states:
<!-- Wrong: Agents trying to mutate block ownership or states --> <div class="product_card" data-agent="BlockOwnershipChanger"> <!-- There's no concept of 'BlockOwnershipChanger' --> </div>
- Agents should enhance or add behaviors, not shift state control from the Observer.
Agent Scope & Examples
Copy link to this sectionCross-Layer Scope
Copy link to this sectionAgents can appear:
- System Layer (L1)
<body class="matrix--shop" data-agent="Analytics">
for global analytics
- Context Layer (L2)
<main class="context--catalog" data-agent="InfiniteScroll">
for context-level infinite scrolling
- Block Layer (L3)
<article class="product_card" data-agent="RevealAnimation">
for repeated animations
- Tail Layer (L5)
<div class="-image" data-agent="LazyLoad">
for localized behavior
Since Agents don’t claim ownership, the same agent can appear multiple times if needed, e.g., multiple <div data-agent="LazyLoad">
throughout the page.
Typical Agent Examples
Copy link to this section- RevealAnimation
- Fades in or slides in a block/tail element when it enters the viewport.
- InfiniteScroll
- Automatically loads more items at the bottom of a listing (often attached at a context layer).
- LazyLoad
- Defers loading images until they’re visible in the viewport.
- SystemAnalytics
- Attaches a site-wide analytics script to
<body>
for capturing events.
- Attaches a site-wide analytics script to
Example Usage in HTML
Copy link to this section
<body class="matrix--shop"
data-agent="SystemAnalytics">
<main class="context--catalog"
data-agent="InfiniteScroll">
<article class="product_card --featured"
data-observer="ProductObserver" <!-- Observer owns block states -->
data-agent="RevealAnimation"> <!-- Agent adds a reveal effect -->
<div class="-image"
data-agent="LazyLoad"> <!-- Lazy loading for images -->
<img src="product.jpg" />
</div>
</article>
</main>
</body>
Key Observations:
<body>
usesdata-agent="SystemAnalytics"
for global analytics.<main>
usesdata-agent="InfiniteScroll"
for context-level pagination logic.<article>
simultaneously hasdata-observer="ProductObserver"
(lifecycle & states) anddata-agent="RevealAnimation"
(visual enhancement).- A tail element (
-image
) hasdata-agent="LazyLoad"
, meaning it only loads images upon scroll.
DOs and DON’Ts
Copy link to this sectionDO:
- Use Agents wherever you need a self-contained feature or utility.
- Attach an agent to any layer without fear of collisions with Observers or other Agents.
- Keep each agent’s logic modular (usually a small ES6 class or object).
- Maintain naming consistency—each agent should clearly reflect its purpose (e.g.,
LazyLoad
,RevealAnimation
).
DON’T:
- Attempt to manage or override block states or lifecycle from an agent (that belongs to the Observer).
- Attach multiple Agents doing the same job on the same element (risk of unexpected conflicts).
Relationship with Observers (data-observer)
Copy link to this sectionObservers claim block-level lifecycle control, manage states, and ensure consistent resource usage.
Agents provide additional behaviors at any layer without interfering with the Observer’s sovereignty or states.
Coexistence:
<article class="product_card --featured"
data-observer="MediaPlayerObserver"
data-agent="RevealAnimation">
<!-- Observer = block-level authority; Agent = cross-layer effect -->
</article>
Result: Each area of concern (block lifecycle vs. cross-layer behavior) remains separate and conflict-free. Observers focus on block states, and Agents handle repeated or global tasks.
Key Takeaways
Copy link to this section- Agents can be placed at L1–L5 for reusable behaviors without claiming the block.
- Because Agents are easily dropped in or invoked, you can add or remove features without rewriting block logic.
- Teams quickly see an agent’s purpose from
data-agent="Xxx"
across the codebase.
data-agent
attaches utility or cross-layer behaviors at any layer, never usurping the block observer’s role. This ensures a clean, predictable layering of advanced front-end features under the Blocktail framework.