Custom Code Block
Custom Code live demo
A scoped micro-interaction
HTML provides the structure, CSS owns the presentation, and vanilla JavaScript enhances the button.
Ready
Use Custom Code for the smallest trusted fragment that standard Luna blocks cannot represent: a bespoke calculator, configurator, visualization, or micro-interaction. The live block above uses semantic HTML, scoped CSS, and progressive vanilla JavaScript.
Properties

Properties contains three code editors. Keep the fragment self-contained, trusted, and as small as possible; surrounding headings, copy, media, navigation, forms, and calls to action should remain standard Luna blocks.
HTML
HTML defines the semantic structure rendered in the editor preview and published View. Script tags, inline event handlers, and javascript: URLs are rejected or stripped, so use ordinary elements, meaningful landmarks, labels, and accessible names.
CSS
CSS is scoped to this block: selectors and keyframe names are rewritten so the fragment does not leak into the page. External @import rules are not supported. Prefer fluid sizing, wrapping, clamp(), and Luna theme variables over fixed desktop-only values.
JavaScript
JavaScript must be vanilla code. It runs with root bound to this block, so query only inside root. When you attach listeners, observers, or timers, return a cleanup function that removes them.
Layout
Custom Code is grid-only and frame-driven, with a documented starting frame of 12 columns by 8 rows. Choose the frame from the intended composition, then make the inner CSS responsive. The demo uses the complete article width at every breakpoint and keeps an intentional eight-row frame.
Behavior
JavaScript is progressive enhancement after load. Essential meaning and primary actions must remain understandable without it. Avoid cookies, storage, global DOM mutation, external requests, dependency loaders, secrets, heavy loops, or unbounded timers unless the integration has been explicitly reviewed.
Style Panel

The Style Panel controls only the outer Frame. Inner elements remain styled by the block’s scoped CSS, so keep frame treatment and fragment styling conceptually separate.
Frame
Frame supports spacing, background, borders, and effects in its Default state. Its hover tab is disabled. Use the Frame for the block boundary; use scoped CSS for the markup rendered inside it.
Motion
Custom Code supports the standard block entrance effects. Keep entrance motion short and nonessential. Inner animation belongs in scoped CSS or JavaScript, must honor prefers-reduced-motion, and must never be required to understand or operate the fragment.
Property summary
HTML — trusted semantic markup rendered in the editor preview and published page.
CSS — block-scoped styles; external imports are not supported.
JavaScript — vanilla progressive enhancement with root scoped to this block and an optional cleanup function.
Animation Effects — the standard entrance motion applied to the outer block.
Responsive behavior
The outer grid frame is intentional at desktop, tablet, and mobile. Inside the frame, use fluid lengths, wrapping, minmax(), clamp(), and media or container queries so content does not depend on scale-down.
Verify the real View at 1440px, 991px, and 375px. Confirm that the fragment stays inside its frame, text remains readable, controls retain at least a 44px target, and neither the block nor the page creates horizontal overflow.
Accessibility
• Start with semantic HTML and give every control an accessible name.
• Preserve keyboard operation, a visible focus state, and a logical reading order.
• Announce meaningful asynchronous results with an appropriate live region, without creating repetitive interruptions.
• Respect prefers-reduced-motion and never rely on color, position, or animation alone.
Common mistakes
• Rebuilding text, buttons, cards, forms, media, or layout that standard Luna blocks already provide.
• Querying document instead of root, leaking global styles, or mutating page-wide DOM.
• Placing secrets, private keys, personal data, or untrusted third-party code in the browser.
• Adding listeners, observers, or timers without cleanup.
• Designing for one fixed width and relying on automatic scale-down instead of responsive inner CSS.
• Choosing an oversized frame with empty space or a frame too small for the intended interaction.
Questions, ideas, or bugs?
Explore what we’re building next, ask the Luna team for help, or send a focused bug report.