Injection Patterns
Use plain browser JavaScript for injected files. The script runs inside the page after navigation, so there is no require, no filesystem access, and no Node globals.
Minimal pattern
(() => {
const target = [...document.querySelectorAll("section")].find((node) =>
node.textContent.includes("Search when the task needs capability"),
);
if (!target) return;
target.setAttribute("data-proto-section", "catalog");
const style = document.createElement("style");
style.textContent = `
[data-proto-section="catalog"] {
border: 1px solid rgba(251, 146, 60, 0.24);
border-radius: 28px;
background: linear-gradient(180deg, rgba(255,255,255,0.03), rgba(255,255,255,0.01));
}
`;
document.head.appendChild(style);
})();Reliable selection
Use this order of preference:
- Visible headings, labels, and placeholder text.
- Stable landmarks such as
main,header,section, forms, or search inputs. - Temporary
data-proto-*attributes that your injected script adds itself. - Existing class selectors only when the page offers nothing more stable.
CSS-only changes
Prefer CSS injection when the experiment is purely visual:
- spacing
- panel backgrounds
- borders and shadows
- typography scale
- section emphasis
- responsive layout tweaks
Inject one style tag instead of scattering many inline styles across nodes.
DOM restructuring
Use JavaScript injection only when the layout must change structurally:
- reorder cards
- wrap content in a new shell
- move badges near headings
- insert helper labels before inputs
Keep DOM edits idempotent. If the script runs twice, it should not duplicate badges, wrappers, or style tags.
Review loop
- Capture a baseline screenshot.
- Inject the smallest experiment that answers the current design question.
- Capture the prototype at desktop and mobile widths.
- Write down what improved, what regressed, and what should become a real code change.
Worked example
On https://forgedemy.org/skills, a good first pass was:
- strengthen the hero with a larger shell and sharper headline scale
- frame the catalog section as the main action zone
- give cards more separation and a stronger top accent
- add a small search caption above the input to clarify the intended flow
That experiment was achieved entirely by annotating sections with data-proto-* attributes, injecting one style block, and screenshotting the result without touching app source.