Skip to content

[Feature]: Add a standard 'userData' property for custom attributes with full JSON serialization support,just like Three.js #10887

@canzoneyu

Description

@canzoneyu

CheckList

  • I agree to follow this project's Code of Conduct
  • I have read and followed the Contributing Guide
  • I have searched and referenced existing issues, feature requests and discussions
  • I am filing a FEATURE request.

Description

Is your feature request related to a problem? Please describe.
Currently, when developers need to attach custom application-specific data to Fabric.js objects (e.g., database IDs, metadata, business logic flags), they have to manually extend the toObject/toJSON methods or rely on the customProperties static field . While these methods work, they lead to fragmentation:

Inconsistency: Every project implements custom property handling differently (some override prototypes, others pass property arrays to toJSON).

Verbose API: Calling canvas.toJSON(['customId', 'metaData']) every time is repetitive and error-prone .

Type Safety Issues: In TypeScript projects, manually extending interfaces for every new property adds boilerplate .

A dedicated, officially supported container for custom data would unify these practices.

Describe the solution you'd like

I propose adding a standard userData property (of type any or object) to all fabric.Object instances. This property would serve as a reserved namespace for developers to store arbitrary data.

Key Requirements:

Automatic Serialization: The userData object should be included by default in the JSON output of toObject() and toJSON() without requiring additional parameters .

Deserialization Support: When using canvas.loadFromJSON(), the data should be automatically restored back to the userData property of the recreated objects .

TypeScript Integration: The IObjectOptions interface should be updated to include userData?: any; to allow for type-safe extensions via generics .

// Creating an object with user data
const rect = new fabric.Rect({
  left: 10,
  top: 10,
  width: 20,
  height: 20,
  userData: {
    id: 'abc-123',
    editable: true,
    tags: ['important', 'draft']
  }
});

canvas.add(rect);

// Serialization - userData is automatically included
const json = JSON.stringify(canvas.toJSON()); 
// Expected output contains: "userData":{"id":"abc-123","editable":true,"tags":[...]}

// Deserialization - userData is automatically restored
canvas.loadFromJSON(json, () => {
  console.log(canvas.item(0).userData.id); // 'abc-123'
});

Static customProperties: Currently, we can set fabric.Object.prototype.customProperties = ['userData'] . However, this is a workaround that isn't obvious to new users and feels like configuring a global rather than using a built-in feature.

Overriding toObject: Manually extending the prototype to include custom properties works but pollutes the prototype chain and can lead to conflicts if multiple libraries do this .

Property Arrays: Passing property names to toJSON() every time is not a sustainable API for large applications .

Additional context
This feature is common in many mature graphics libraries (e.g., Konva.js has a similar attrs or id pattern) and would significantly reduce boilerplate for developers building complex applications on top of Fabric.js (like design tools, diagram editors, etc.).

The implementation would likely involve modifying the core serialization logic in src/shapes/object.class.js to include this.userData in the default property set, similar to how id or data might be handled.

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions