Developers often assume that everyone working with HTML also understands JavaScript. This assumption creates barriers for designers and content creators who primarily work with markup and styling. A well-designed HTML API should make functionality accessible through declarative markup rather than requiring script initialization.
Consider the difference between initializing an autocomplete feature using jQuery UI versus using native HTML5:
<!-- jQuery UI approach requires JavaScript configuration -->
<div class="ui-widget">
<label for="tags">Tags: </label>
<input id="tags">
</div>
<script>
$(function() {
const suggestions = [
"ActionScript",
"AppleScript",
"Asp",
"BASIC",
"C"
];
$("#tags").autocomplete({
source: suggestions
});
});
</script>
The above example assumes knowledge of variables, arrays, selectors, and event handling. Compare this to the native HTML5 equivalent:
<!-- Native HTML5 approach uses only markup -->
<div class="ui-widget">
<label for="tags">Tags: </label>
<input id="tags" list="languages">
<datalist id="languages">
<option>ActionScript</option>
<option>AppleScript</option>
<option>Asp</option>
<option>BASIC</option>
<option>C</option>
</datalist>
</div>
The second version requires no scripting knowledge and provides immediate clarity about what values are available.
Initialization Strategies
When designing an HTML API, automatic initialization based on specific selectors improves usability. For instance, libraries like Awesomplete initialize elements automatically when they detect class="awesomplete".
For broader applications, consider default behaviors that can be customized via attributes. Stretchy.js automatically adjusts form element sizes but allows filtering through data-stretchy-filter for targeted control.
Minimal Markup Requirements
Avoid requiring complex wrapper structures around target elements. Generate necessary DOM nodes programmatically unless their presence benefits users without JavaScript (e.g., progressive enhancement scenarios).
To balance flexibility with simplicity, check if required containers already exist before creating them dynamically:
const containerExists = element.closest('.custom-wrapper');
if (!containerExists) {
// Create new wrapper
}
Configuration Through Attributes
Use data-* attributes for configuraton options where possible. Namespace these attributes (data-libraryname-*) to prevent conflicts with other libraries. Boolean settings should follow standard HTML conventions - presence indicates true regardless of value.
Class-based toggles offer another option for boolean flags:
<!-- Using classes for boolean settings -->
<div class="feature-enabled">...</div>
<div class="no-transitions">...</div>
For grouped permissions or related flags, space-separated lists provide cleaner syntax than multiple discrete attributes:
<div data-permissions="read write execute admin"></div>
Complex configurations such as lists or structured data can reference other elements by ID:
<input data-suggestions="#my-list">
<datalist id="my-list">
<option>Option 1</option>
<option>Option 2</option>
</datalist>
Some advanced settings may require JavaScript functions. Reserve these for cases where declarative approaches fall short:
new Autocomplete('#input', {
filter: (text, input) => text.toLowerCase().includes(input.toLowerCase()),
sort: (a, b) => a.localeCompare(b)
});
Inheritance and Cascading
Allow configuration inheritance from parent elements to reduce repetition across multiple instances. Prism syntax highlighter demonstrates this pattern effectively:
<body class="language-javascript">
<pre><code>// Automatically inherits language from body</code></pre>
<pre><code class="language-python"># Override inherited setting</code></pre>
</body>
CSS custom properties offer similar cascading behavior with runtime access:
const themeColor = getComputedStyle(element)
.getPropertyValue('--theme-color');
Global Settings
Provide global configuration options through the script tag loading your library:
<script src="library.js" data-option="value"></script>
Access current script via document.currentScript which has broad browser support. Alternatively, allow global settings on <html> or <body> elements with documented precedence rules.
Documentation Considerations
Structure documentation starting with declarative usage patterns before introducing JavaScript interfaces. Avoid leading with code samples containing regular epxressions, framework terminology, or programming concepts unfamiliar to designers.
Place JavaScript-specific examples under sections labeled 'Advanced Usage' or 'Programmatic Control'. This ensures primary audiences aren't discouraged by perceived complexity.