This article starts a new design-notes series for Cotomy. The purpose here is not step-by-step usage, but design intent.
In practical guides, we discuss “how to use” APIs. Here, the focus is different:
I want to explain why this design exists, which failure modes it was meant to prevent, and which trade-offs were accepted on purpose.
This first note focuses on the class that sits at the start of that model: CotomyElement.
Why This Series
As projects grow, implementation details change often. But architectural intent changes more slowly.
If that intent is not documented, teams eventually keep only surface patterns, not reasons. Then the same arguments repeat in every project:
Why not use direct DOM APIs everywhere, let CSS live independently, and patch conflicts later? Why not just pick a familiar utility layer and move on?
This series records those questions explicitly, not as doctrine but as design history.
Why Start from a DOM Wrapper Boundary
CotomyElement started from one practical need: I wanted to handle DOM elements with the same workflow every time.
When using raw HTMLElement directly at scale, recurring problems appear:
APIs get scattered across native methods and ad-hoc helpers, null checks become repetitive and inconsistent, and type safety depends on local discipline instead of a shared entry point.
The initial requirement was simple: “Even a thin wrapper is fine, as long as the entry point is unified.”
But in practice, this became more than convenience. In Cotomy projects, DOM operations are intentionally routed through one boundary so that design leverage can appear:
future behavior can be added in one place instead of scattered handlers, logging and tracing can stay on one operational surface, and debugging can start from a predictable boundary instead of random selectors.
In this note, “boundary” means a responsibility line: where element handling enters a shared runtime model instead of ad hoc local code.
So yes, at first glance this can look jQuery-like. But the objective is different.
jQuery historically optimized cross-browser convenience and chaining, while CotomyElement is focused on runtime boundary discipline in TypeScript-first projects.
It is not “DOM sugar” as a goal. It is a structural boundary for predictable behavior.
HTML and CSS Distance as a Failure Pattern
A common breakdown pattern is distance. HTML structure and CSS responsibility are separated so far that nobody can explain “which style is authoritative for this element”.
Typical failure shape:
<section id="user-card">
<h3 class="title">User</h3>
</section>
/* file A */
.title { font-size: 14px; }
/* file B */
#dashboard .title { font-size: 16px; }
/* file C */
.card .title { letter-spacing: .04em; }
Each rule can be locally reasonable. Together, the actual screen becomes context-dependent and fragile.
Cotomy’s design stance is to start from DOM boundary first, so that:
structure, style, and behavior can stay in one operational context.
This does not mean one file for everything. It means responsibility should stay traceable from an element outward. When that line is explicit, style ownership is easier to follow.
Raw DOM Failure Pattern in Real Screens
Another frequent failure is scattered direct selector logic.
document.querySelector(".title")!.classList.add("active");
document.querySelector(".title")!.setAttribute("data-state", "open");
Each line can look harmless. But once this pattern spreads across files and handlers:
ownership of state transitions becomes unclear, local DOM changes bypass screen-level intent, and refactor impact is hard to estimate before regressions appear.
So the problem is not only syntax, but responsibility drift around element state.
Why Not Just Use jQuery
At the time of choosing a baseline, jQuery was a rational option. It still has proven history and broad familiarity.
The hesitation was not “jQuery is bad”. The hesitation was long-term direction:
trend and ecosystem fit for current TypeScript-heavy workflows, type safety and intent expression, and readability under large codebases where boundaries matter more than shortcuts.
To be explicit and fair:
Cotomy has only just been published, so adoption is still minimal. Its track record is currently limited to the author’s own production use so far, although it is already used via npm in several projects and is being actively maintained.
The difference is architectural role:
jQuery is primarily a convenience-oriented function layer, while CotomyElement is a responsibility boundary for DOM operations.
What Cotomy does have in that boundary model:
the author understands the full design and implementation surface, fixes can be made immediately when the model needs adjustment, and architecture intent can stay aligned with implementation through one accountable owner.
For internal or responsibility-heavy systems, that alignment matters.
Why CotomyElement Became More Than a Thin Wrapper
If it only wrapped querySelector, it would not solve enough. The class intentionally supports multiple entry patterns.
Entry variants
byId(…) is for stable identity contracts, selector-based retrieval through first(…) and find(…) is for screen lookup, and creation from HTML string is for explicit runtime generation.
These variants exist not for convenience, but to prevent divergence in how elements enter the runtime model.
Examples:
import { CotomyElement } from "cotomy";
const byId = CotomyElement.byId("order-form");
const firstError = CotomyElement.first(".field-error");
const rows = CotomyElement.find(".result-row");
const created = new CotomyElement('<div class="notice">Ready</div>');
import { CotomyElement, CotomyWindow } from "cotomy";
const notice = new CotomyElement('<div class="notice">Saved</div>');
CotomyWindow.instance.initialize();
CotomyWindow.instance.body.append(notice);
CotomyElement.find(".field-error").forEach(e => e.attribute("data-visible", "false"));
Problems this solved
It reduced initialization-order friction by keeping creation and binding in one model, improved null-safety discipline through explicit return behavior, and unified handling for existing DOM and generated DOM.
Why not rely on direct native DOM element handling
Directly constructing HTMLElement is not the practical center of browser UI. Actual screens mix server-rendered nodes and runtime-generated nodes.
Designing around CotomyElement gives one operational surface for both, without splitting the mental model by origin.
Not SPA-Centric, But Not Anti-SPA
Officially, Cotomy is not a SPA-specialized framework. That is intentional, and it is a design premise rather than a limitation.
However, this is not a rejection of SPA architecture. My view is that sufficiently large SPA-style systems are still possible, provided the design keeps UI framework concerns separate from runtime boundaries. The boundary model remains valid regardless of navigation style.
Outside a dedicated component framework layer, many concerns can still be handled coherently in TypeScript:
screen control, state transitions, and operational behavior.
This is a design direction, not a universal guarantee. The key is to preserve explicit boundaries, whichever navigation style is used.
Conclusion
CotomyElement was not introduced to add another utility API. It was introduced to establish a stable boundary where DOM handling becomes repeatable, explainable, and accountable.
From that boundary, other Cotomy layers become extensions of the same idea:
clear responsibility, explicit contracts, and consistent runtime behavior.
That is why this series starts here.
Design Series
This article is part of the Cotomy Design Series, which explores architectural decisions behind the framework.
Series articles: CotomyElement Boundary, Page Lifecycle Coordination , Form AJAX Standardization , Inheritance and Composition in Business Application Design , API Exception Mapping and Validation Strategy , and Why Modern Developers Avoid Inheritance .