@cocreate/elements

中文文档
2.0.2发布于 2026/11/07AGPL-3.0CommonJS近 30 天下载 1958

Fetch content into any html element by using html5 attributes to query data stored in CoCreate headless CMS. If data is changed it will instantly reflect in html tags as changes are broadcasted in realtime

原始使用文档
文档目录35 节
  1. Documentation
  2. Table of Contents
  3. Features
  4. Installation
  5. CDN
  6. Usage
  7. Display a Value
  8. Edit a Value
  9. Group Fields Into a Document
  10. Create a Record
  11. Render a List
  12. Delete a Record
  13. How it Works
  14. The Data Scope
  15. Core Attributes
  16. Behavior Attributes
  17. Key Expressions
  18. Value Pipeline
  19. Forms
  20. Scope Inheritance
  21. Generated Ids
  22. Saving
  23. Reset
  24. Filtering and Lists
  25. Realtime Synchronization
  26. Actions
  27. Element Methods
  28. JavaScript API
  29. Behavior Notes
  30. Announcements
  31. Roadmap
  32. How to Contribute
  33. About
  34. License
  35. Enter shortcuts for action buttons

@cocreate/elements

Bind any HTML element directly to your data using HTML5 attributes. An element declares where its value lives — a storage, database, array, document, and key — and the module handles the rest: reading the value in, writing changes back, and keeping it synchronized in realtime as other clients and servers broadcast updates. There is no query code, no fetch layer, and no view model. The markup is the data binding.


Documentation

For a complete guide and working demo refer to the documentation.

Table of Contents


Features

  • Declarative Data Binding: Point an element at a document field and it reads, renders, and persists that field without any application code.
  • Automatic CRUD Resolution: The operation is inferred from the attributes present, so the same markup creates a record when it has no id and updates it when it does.
  • Realtime Two-Way Sync: Elements subscribe to their own data scope and update instantly when the underlying record changes anywhere in the system.
  • Batched Reads: Elements sharing a scope are collected into a single query, so a document bound across twenty fields performs one read.
  • Forms as Documents: A form groups fields into one payload, propagates its scope to its children, and saves them as a single operation.
  • Value Transformation Pipeline: Type coercion, prefixes, suffixes, replacements, casing, and encoding are applied on the way in and out.
  • Filter Integration: Works with @cocreate/filter to drive queries, sorting, pagination, and infinite scroll from markup.
  • Action Integration: Registers save, delete, and reset so persistence composes into action chains.
  • Automatic Binding: Elements inserted later, including rendered templates, are initialized and subscribed automatically.

Installation

npm install @cocreate/elements
yarn add @cocreate/elements

CDN

<script src="https://cdn.CoCreateJS.com/elements/latest/CoCreate-elements.min.js"></script>

Usage

Display a Value

<span array="users" object="64b9a32e18f21bc56789abcd" key="name"></span>

The element reads the name field of that document and renders it. If the document changes anywhere in the system, the element updates.

Edit a Value

<input
    array="users"
    object="64b9a32e18f21bc56789abcd"
    key="email"
    realtime="true" />

With realtime, every keystroke persists the field. Without it, the value is saved when a save action runs.

Group Fields Into a Document

<form array="users" object="64b9a32e18f21bc56789abcd">
    <input key="name" />
    <input key="email" />
    <textarea key="bio"></textarea>

    <button actions="save">Save</button>
</form>

The form propagates its scope to every field, so each input only declares its key. Saving sends one payload containing all three fields.

Create a Record

<form array="users" object>
    <input key="name" />
    <input key="email" />

    <button actions="save, reset">Create</button>
</form>

An empty object attribute means "no document yet". On save the module issues a create, then writes the new id back into the form and its fields, so subsequent saves update the same record.

Render a List

<div
    array="users"
    object
    filter-query-key="status"
    filter-query-value="active"
    filter-limit="20"
    filter-sort-key="name"
    render-query="[template]">
    <div template>
        <span>{{object.name}}</span>
        <span>{{object.email}}</span>
    </div>
</div>

Delete a Record

<button
    array="users"
    object="64b9a32e18f21bc56789abcd"
    actions="delete">
    Delete
</button>

Multiple targets can be selected with delete-query. Each target declares its own CRUD scope; object targets sharing the same storage, database, and array are sent in one delete request.

<button
    actions="delete"
    delete-query="$document [data-delete]:checked[]">
    Delete selected
</button>

<input
    type="checkbox"
    data-delete
    array="users"
    object="64b9a32e18f21bc56789abcd" />

How it Works

  1. On load the module scans for elements declaring storage, database, array, or render-json.
  2. Each element's attributes are parsed into a normalized CRUD payload, and its type is inferred from which attributes are present.
  3. A dataKey is generated from the scope, and every element sharing that key is grouped together. Field-level key is deliberately excluded from document-scope keys so all fields of one document share a single scope.
  4. The scope is subscribed to over the socket so future changes are pushed to every bound element.
  5. Reads are debounced and batched, so one query serves every element in the scope.
  6. The response is distributed to each element, which extracts its own field and renders it through the value pipeline.
  7. Editable elements listen for input. When realtime is enabled, changes persist automatically.
  8. Writes resolve to a create or an update depending on whether an id is present, and the resulting id is propagated back into the markup.

The Data Scope

Attributes describe a hierarchy, from the storage provider down to a single field.

LevelAttributeDescription
StoragestorageStorage provider or alias
DatabasedatabaseDatabase name
ArrayarrayCollection, table, or dataset
IndexindexIndex within the array
ObjectobjectDocument id, empty for a new document
KeykeyField within the document

The type of operation is inferred from the deepest level present:

Attributes PresentInferred Type
object or key (with array)object
index (with array)index
arrayarray
databasedatabase
storagestorage

Any of these may hold a comma separated list to target several scopes at once.

<div array="users, admins" key="name"></div>

Core Attributes

AttributeDescription
storageStorage provider targeted by the operation
databaseDatabase name, defaults to the organization
arrayCollection or table name
indexIndex scope within the array
objectDocument id. Empty creates a new document, ObjectId() generates one, pending marks a create in flight
keyField path within the document
updateNameRename target when updating a named scope
organization_idTenant identifier
hostHost context
apikeyAPI key used for the operation
roomRealtime room scope
referenceWhen false, strips storage metadata from the returned object

Behavior Attributes

Each of these accepts "false" to opt out, and most default to enabled.

AttributeDescription
crud="false"Excludes the element from binding entirely
read="false"Element never reads, it only writes
save="false"Element never writes, it only reads
update="false"Element ignores incoming updates after its first read
listen="false"Element ignores broadcasts, but still accepts its own reads
deleteMarks the element as a delete target
upsertCreates the document if it does not exist when updating
realtime="true"Persists on every input event
crdt="true"Routes text edits through collaborative merge instead of overwriting
broadcast="false"Suppresses broadcasting the change to other clients
broadcast-sender="false"Suppresses echoing the change back to the sender
broadcast-client="false"Suppresses propagation to other tabs
form-attributes="false"Prevents the element from inheriting its form's scope
resetControls reset behavior, see Forms
splice, slice, updateArray mutation modes when the key targets an index

Key Expressions

key supports more than a plain field name.

ExpressionResolves To
nameA top-level field
profile.address.cityA nested field via dot notation
tags[0]An array member by index
{}The entire document, for reading or writing whole objects
tags.$lengthThe length of an array field
$dataThe complete response payload
$object / $arrayThe full result collection for the current type
<span array="posts" object="64b9a32e18f21bc56789abcd" key="comments.$length"></span>

Value Pipeline

Values are transformed on the way in and out by @cocreate/element-prototype. These attributes apply to any bound element.

AttributeDescription
value-typeCoerces the value, for example json, html, text, array, number
value-prefixPrepends a string
value-suffixAppends a string
value-replaceReplaces the first match of a pattern
value-replaceallReplaces every match of a pattern
value-replacementReplacement string used by the above
value-lowercaseLowercases the value
value-uppercaseUppercases the value
value-encodeEncodes the value, for example base64 or URI
value-decodeDecodes the value
value-remove-queryRemoves matching nodes before reading an HTML value
value-dispatchClears the value when a query returns no results
value-bubblesBubbles the synthetic input event
value-queryComposes this element's value from other elements
value-attributeWrites the composed value to an attribute instead of the value
<textarea
    array="files"
    object="64b9a32e18f21bc56789abcd"
    key="src"
    value-type="text"
    value-replaceall="/```html\n|\n```/g"></textarea>

Forms

Scope Inheritance

A form propagates organization_id, host, storage, database, array, index, object, and key to descendant elements that participate in binding. Add form-attributes="false" to an element that must keep its own scope.

Generated Ids

object="ObjectId()" generates a client-side id at initialization, letting related records reference each other before they are persisted.

Saving

Saving a form collects every bound field into one payload per type and issues a single operation. Saving an individual element inside a form delegates to the form, so a field never writes a partial document by accident.

Reset

The reset attribute controls what a reset preserves.

ValueDocument IdValue
omittedclearedcleared
objectclearedpreserved
valuepreservedcleared
falsepreservedpreserved
<input key="organization_id" value="$organization_id" reset="false" hidden />

Filtering and Lists

Filter attributes from @cocreate/filter compose directly with a bound scope to drive queries, sorting, limits, and pagination.

<div
    array="posts"
    object
    filter-query-key="status"
    filter-query-value="published"
    filter-sort-key="created.on"
    filter-sort-direction="desc"
    filter-limit="10"
    render-query="[template]">
    <div filter-on="scroll" filter-query="$parent"></div>
    <article template>{{object.title}}</article>
</div>

A filter element may target another element with filter-query, so an input elsewhere on the page can drive a list's query. Changing a filter re-reads the scope and re-renders.


Realtime Synchronization

Every scope subscribes over the socket on two channels: one for the specific document and one for the collection it belongs to. A change therefore reaches both the element bound to that record and any list rendering the collection.

Subscriptions are reference counted. When the last element bound to a scope is removed from the DOM, the module unsubscribes automatically, so rendered lists and modals do not leak channels.


Actions

ActionCompletion EventBehavior
savesavedPersists the element, or its form when it belongs to one
deletedeletedDeletes the bound document, honoring delete-query for multiple targets
resetresetRestores the form according to each field's reset attribute
<button actions="save, reset">Save and clear</button>

Element Methods

Binding attaches methods directly to elements, so imperative code and action chains share one implementation.

MethodAvailable OnDescription
getValue()any bound elementReads the value through the value pipeline
setValue(value)any bound elementWrites the value and dispatches input and change
read()any bound elementRe-reads the element's scope
save()any bound element or formPersists the element or the whole form
getData()formsReturns the assembled payload without saving
getFilter() / setFilter()filtered elementsReads or replaces the active filter, re-reading the scope
const form = document.querySelector("#profile");
const payload = await form.getData();
await form.save();

JavaScript API

import elements from "@cocreate/elements";

elements.init();
elements.init(document.querySelector("#profile"));
MethodDescription
init(element)Initializes an element, a collection, or the whole document
read(element, data, dataKey)Reads a scope and distributes the result
save(element, action)Persists an element or form
getData(element)Assembles the payload for an element or form
getDataObject(element)Normalizes an element's attributes into a CRUD payload
reset(action)Runs reset logic for a form
setDataType(element, data, action)Applies a created record's id back into the markup
elements, keys, formsInternal registries of bound elements and scopes

Behavior Notes

  • An element must declare storage, database, or array to be initialized. A lone object or key is not a binding, which is why fields inside a form rely on inherited scope.
  • Reads are debounced for 500ms and deduplicated per scope, so many elements binding one document produce a single query.
  • An element reads once per scope. Changing a filter or calling read() resets that state.
  • A document id must be a 24 character hexadecimal value, or the placeholders pending and ObjectId().
  • Elements rendered on the server carry a rendered marker and skip their first client render, preserving server output.
  • Save on input requires realtime, and never applies to a _id field.
  • When crdt is enabled and a document id exists, text edits merge collaboratively rather than overwriting.

Announcements

All updates to this library are documented in our CHANGELOG and releases. You may also subscribe to email for releases and breaking changes.


Roadmap

Upcoming enhancements include:

  • Expanded array mutation operators
  • Optimistic write rollback on failure
  • Schema-aware value coercion
  • Development mode diagnostics for unbound and misconfigured scopes
  • Devtools inspection of an element's scope and subscriptions

If you are interested in the future direction of this project, please take a look at our open issues and pull requests. We would love to hear your feedback.


How to Contribute

We encourage contribution to our libraries (you might even score some nifty swag), please see our CONTRIBUTING guide for details.

We want this library to be community-driven, and CoCreate led. We need your help to realize this goal. To help make sure we are building the right things in the right order, we ask that you create issues and pull requests or merely upvote or comment on existing issues or pull requests.

We appreciate your continued support, thank you!


About

CoCreate-elements is guided and supported by the CoCreate Developer Experience Team.

Please Email the Developer Experience Team here in case of any queries.

CoCreate-elements is maintained and funded by CoCreate. The names and logos for CoCreate are trademarks of CoCreate, LLC.


License

This software is dual-licensed under the GNU Affero General Public License version 3 (AGPLv3) and a commercial license.

  • Open Source Use: For open-source projects and non-commercial use, this software is available under the AGPLv3. The AGPLv3 allows you to freely use, modify, and distribute this software, provided that all modifications and derivative works are also licensed under the AGPLv3. For the full license text, see the LICENSE file.

  • Commercial Use: For-profit companies and individuals intending to use this software for commercial purposes must obtain a commercial license. The commercial license is available when you sign up for an API key on our website. This license permits proprietary use and modification of the software without the copyleft requirements of the AGPLv3. It is ideal for integrating this software into proprietary commercial products and applications.

If you have not purchased a commercial license and intend to use this software for commercial purposes, you are required to sign up for an API key on our website.

Enter shortcuts for action buttons

Set submit-query on a form or an inner section to explicitly select the action element Enter should click from a single-line input:

<form>
    <section submit-query="#next-step">
        <input name="name" />
        <button id="next-step" type="button" actions="disabled, validate, save, disabled">Next</button>
    </section>
</form>

The nearest submit-query within the form wins. Its value uses CoCreate query selectors, resolved from the element carrying the attribute. The resolved target must have actions, belong to the same form, and be visible and enabled. No action target is inferred when the attribute is absent. Empty or unresolved queries, multiple returned targets, and disabled targets do not fall through to native submission. Held Enter does not repeatedly activate the button.

Textareas, selects, editable content, input widgets, composition, modified keystrokes, and events already handled by another listener keep their normal keyboard behavior. This shortcut calls .click(); it does not submit the form itself. Existing action/method handling remains separate, and a submit button with actions can still preprocess an external submission through its chain.

版本与发布记录

@cocreate/elements 共发布 269 个版本,首次发布于 2021/10/19;过去 12 个月发布了 15 个版本。

版本发布日期距今
2.0.2latest2026/11/073 天前
2.0.12026/11/064 天前
2.0.02026/11/037 天前
1.48.02026/10/2120 天前
1.46.02026/08/043 个月前
1.45.02026/08/013 个月前

关于 @cocreate/elements 的常见问题

@cocreate/elements 是什么?

Fetch content into any html element by using html5 attributes to query data stored in CoCreate headless CMS. If data is changed it will instantly reflect in html tags as changes are broadcasted in realtime

如何安装 @cocreate/elements?

在项目目录运行 npm install @cocreate/elements,或使用 pnpm add / yarn add / bun add。

@cocreate/elements 支持 TypeScript 吗?

该包的 package.json 没有声明类型入口。需要类型提示时,可以在 npm 上查找社区维护的 @types/cocreate__elements 是否存在。

@cocreate/elements 支持 ESM 还是 CommonJS?

以 CommonJS 形式发布,可以直接 require();在 ES Module 项目中也可以用 import 引入(Node.js 会把 module.exports 作为默认导出)。

@cocreate/elements 可以商用吗?

@cocreate/elements 使用 AGPL-3.0 许可。最严格的 Copyleft:除分发外,通过网络向用户提供基于它的服务也需要开源对应源码。闭源 SaaS 使用前务必评估。以上为概括,不构成法律意见,请以许可原文为准。

@cocreate/elements 的下载量有多少?

根据 npm 官方下载统计,@cocreate/elements 在 2026/10/10 – 2026/11/08 这 30 天内被下载 1,958 次,日均约 65 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@cocreate/elements 还在维护吗?

最新版本 2.0.2 发布于 2026/11/07(3 天前);至今共发布 269 个版本,其中过去 12 个月发布了 15 个;首次发布于 2021/10/19。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。