Advice re: tradeoff between controller scope vs markup bloat

I fell in love with Stimulus and am refactoring our controllers one by one.

I’ve now had to make a tradeoff between

  1. Many controller instances with minimal scope, which leads to markup bloat due to common data attributes
  2. Single controller instance with larger scope using event bubbling/delegation with minimal markup

Here’s a greatly simplified example to illustrate the tradeoff.

<ul>
	<li
		data-controller="delete"
		data-delete-id-value="1"
		data-delete-confirm-prompt-value="Really delete?"
		data-action="delete#go"
	>
		1st
	</li>
	<li
		data-controller="delete"
		data-delete-id-value="2"
		data-delete-confirm-prompt-value="Really delete?"
		data-action="delete#go"
	>
		2nd
	</li>
	<!-- ... -->
</ul>

versus

<ul
	data-controller="delete"
	data-delete-confirm-prompt-value="Really delete?"
>
	<li
		data-action="delete#go"
		data-delete-id-param="1"
	>
		1st
	</li>
	<li
		data-action="delete#go"
		data-delete-id-param="2"
	>
		2nd
	</li>
	<!-- ... -->
</ul>

The real case had even more value attributes which did not vary across controller instances. It also involved a large, dynamic <table> with lots of markup in a large template. Every row has a bunch of “action” icons, which will use separate controllers (e.g., hide row, delete model, compose message popup, etc)

Stylistically, my team very much prefers the first approach. The controller markup is localized, making it way easier to reason about.

I refactored it to the second approach because the markup bloat surely carries a penalty. gzip will compress it wonderfully, of course, but the browser will need to parse it and will have to handle a bigger DOM tree. Won’t this get out of hand?

Any advice and/or heuristics are very welcome.

1 Like

Nah, the browser can handle large DOM trees better than, say, heavy use of JavaScript objects in memory.

The beauty of all these attributes on those objects is that there isn’t a huge tree of objects in memory, because Stimulus assumes the DOM is the authority to read from. Even the Values API uses the data attribute on the object as the thing it reads from.

So, many narrow controllers are one large one? I’d say go with your gut: either works, and an extra controller is a small price to pay on the JavaScript loading for the clarity benefits. You’ll bump up against the real constraint of that decision when comes time to organize your controllers per feature or per app section or per component. At that point you might want to re-factor.

Thanks for clarifying.

=> git revert :smiley: