Quick access to guides, API, accessibility, and troubleshooting
Test Code
_parseMarkSpec(spec, base) {
// spec: "3,7-9,15"
const s = new Set();
if (!spec) return s;
for (const part of spec.split(',')) {
const p = part.trim();
if (!p) continue;
const m = p.match(/^(\d+)\s*-\s*(\d+)$/);
if (m) {
const a = parseInt(m[1],10), b = parseInt(m[2],10);
const [lo, hi] = a <= b ? [a,b] : [b,a];
for (let n=lo; n<=hi; n++) s.add(n);
} else {
const n = parseInt(p,10);
if (!isNaN(n)) s.add(n);
}
}
return s;
}
PWAxcode.autoInit();
Markup & Init
Standard Container
Wrap your snippet in a .container.PWAxcode with an optional header/footer and a body that contains exactly one <pre><code>…</code></pre> You can set the language on the wrapper or on <code> via data-lang (e.g. js, html, css, json, sql). Per-snippet behavior (wrap, line numbers, theme, etc.) can be configured with data-attributes.
JS Snippet
console.log('Hello PWAxcode');
Initialize with:
PWAxcode.autoInit();
Bare block (code only).
Use a plain <div class="PWAxcode"> whose textContent is the raw code. No header/footer is rendered. In bare mode the language is chosen in JavaScript (pass lang in options); data-lang is not required.
console.log('Hello PWAxcode');
Initialize with:
con = new PWAxcode(document.getElementById('testCode'), {
bare: true,
lang: 'js',
highlight: true
});
Initialization.
For standard containers, call PWAxcode.autoInit(); and all matching blocks are upgraded automatically.
For bare blocks, instantiate manually. That’s it!
Data-Attributes
This table lists all configurable options for PWAxcode—type and default, what each option does, and the matching HTML data-attribute for auto-init. You can set options in JavaScript or via data-attributes; when both are present, constructor values take precedence. Booleans accept true | false | 1 | 0; numeric sizes accept numbers (px) or CSS lengths (e.g., 420px, 50vh).
HTML attributes → JS options. HTML attributes (kebab-case) map to constructor options (camelCase). Example: data-footer-controls="prev,next" → footerControls: ['prev','next']. Booleans accept true | false | 1 | 0. Numbers accept plain digits (pixels) or CSS lengths (e.g., 420px, 50vh). Arrays can be comma-separated strings or JSON (e.g., data-footer-controls='["prev","next"]'). Constructor options always override data-attributes.
Load code from a URL. Inside the code block you can use data-src="https://example.com/snippet.js" to fetch content. If the request succeeds, the response text replaces the inline code; if it fails, the inline code remains unchanged. Ensure the URL is same-origin or CORS-enabled.
Heads-up.
Fetched content is treated as UTF-8 text. HTTP errors (4xx/5xx) or network failures leave the original inline code in place and log a console warning.
PWAxcode is configurable per-instance and per-snippet. You can pass an options object when you instantiate. Most options have sensible defaults; types are enforced (booleans, numbers, strings, string lists).
Display & Layout
Option
Type / Default
Description
api.setFontSize(px)
px: number → number
Sets the font size (bounded by fontMin/fontMax) and reflows the view. Returns the applied size.
api.zoomIn(step?)
step?: number step = fontStep → number
Zoom in convenience; increments font by fontStep.
api.zoomOut(step?)
step?: number step = fontStep → number
Zoom out convenience; decrements font by fontStep.
Theme name (dark, light, funky, relax, auto, custom).
lang
string = auto
Language ID or auto for auto-detect.
highlight
boolean = false
Start in highlighted (HL) view.
wrap
boolean = false
Soft-wrap long lines.
tabSize
number = 2
Tab width (spaces).
tabs
'both'|'view'|'none' = 'both'
Tab expansion policy / which views to render.
lineNumbers
boolean = true
Show line numbers.
lineNumbersStart
number = 1
First visible line number.
height
number | string | null = null
Fixed height of the body container.
maxHeight
number | string | null = null
Maximum scroll height of the body container.
fade
boolean = false
Enable/disable top/bottom fade shadows.
toolbarVisible
boolean = true
Show/hide the header toolbar.
ruler
boolean = false
Show/hide the column ruler.
rulerStyle
'full'|'tens' = 'tens'
Ruler style.
rulerPosition
'top'|'bottom' = 'top'
Ruler placement.
download
boolean = true
Enable the download action.
downloadContent
'view'|'raw' = 'view'
Which text to download.
filename
string = 'code.txt'
Suggested download filename.
floatBar
boolean = true
Show/hide the floating control bar.
floatBarControls
string[] | CSV = —
Which controls to show (same IDs as footerControls).
floatBarInFullscreen
boolean = true
Keep it visible in fullscreen.
floatBarRemember
boolean = false
Remember last position via localStorage.
playerAutoplay
boolean = false
Auto-start step player.
playerLoop
boolean = false
Loop steps.
playerButtons
boolean = true
Show player buttons.
playerProgress
boolean = true
Show progress indicator.
playerShowNotes
boolean = true
Show notes in player.
playerWaitAfterActionMs
number = 0
Delay after each action (ms).
playerClosePopoverOnStop
boolean = true
Auto-close popover when player stops.
playerStopHoldMs
number = 350
Long-press duration to stop (ms).
showTokens
boolean = false
Toggle token overlay.
footerControls
string[] | CSV = —
Footer controls to render.
footerAlign
'left'|'center'|'right' = 'right'
Footer alignment.
toastPosition
'top'|'bottom' = 'bottom'
Toast placement.
toastMax
number = 3
Max concurrent toasts.
copyToastMs
number = 1200
Auto-dismiss delay for copy toasts.
autoIndent
boolean = true
Apply basic auto-indentation rules.
searchOffsetPx
number = 64
Default top offset reserved by goto / search-scroll.
fontSize
number | null = null
Base font size in px (fallback to CSS vars when null).
fontLineHeight
number | null = null
Base line-height (fallback to CSS vars when null).
fontMin
number = 10
Minimum font size allowed.
fontMax
number = 28
Maximum font size allowed.
fontStep
number = 2
Increment used by zoomIn/zoomOut.
typingCPS
number = 24
Typing speed used by demos (chars/sec).
autoFormatAfterTyped
boolean = false
Auto-format after user input.
fullscreen
boolean = false
Start in fullscreen mode.
compressed
boolean = false
Start in compressed (chrome-less) mode.
markSpec
string = ''
Initial mark specification (e.g., "1,3,10-15").
dedent
boolean = true
Trim common leading indentation.
locale
string = 'en'
UI locale.
translations
object = —
Custom i18n strings.
Notes & Tips
Where to set options
JavaScript (constructor): new PWAxcode(el, { lang:'js', highlight:true, lineNumbers:false });
HTML (auto-init)
At runtime: pxc.setOption('lineNumbers', true); theme via pxc.setTheme('dark'|'light'|'funky'|'relax'|auto'|customId)
Precedence (highest → lowest)
Runtime changes (setOption, setTheme)
Constructor options
Data-attributes on the element
Library defaults
Theming
Pick 'light', 'dark', 'funky', 'relax' or 'auto' at init; switch anytime with setTheme
Custom themes can be bundled/registered and selected by id.
Good to know
Options are per-instance; change them without re-creating the component. Data-attributes are ideal for content sites (static HTML); JS options are best when you need full control or dynamic behavior.
API Methods
This section documents the runtime JavaScript API you can call to control a PWAxcode instance after it’s on the page. You’ll find constructor & helpers, instance controls (rendering, layout, search, folding, ruler).
Display & Layout
api.setFontSize(px: number): number
Sets the font size (bounded by fontMin / fontMax) and reflows the view. Returns the applied size.
api.setFontSize(16);
api.zoomIn(step?: number): number api.zoomOut(step?: number): number api.resetZoom(): { fontSize: number, lineHeight: number }
Convenience zoom controls based on fontStep. resetZoom(); restores the initial font and line-height.
Sets a fixed height or a maxHeight for the body scroll area.
api.setHeights({ height: '400px' });
api.setTabSize(n: number)
Updates the tab stop size (spaces) for both views.
function test() {
const grid = [];
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 4; j++) {
grid.push(`${i},${j}`)
};
}
console.log(grid.join(' '));
}
api.setWrap(on: boolean) api.toggleWrap()
Enable/disable soft line wrapping.
// Intentional ultra-long single line
const wrapLine = ["alpha","beta","gamma","delta","epsilon","zeta","eta","theta","iota","kappa","lambda","mu","nu","xi","omicron","pi","rho","sigma","tau","upsilon","phi","chi","psi","omega","alpha2","beta2","gamma2","delta2","epsilon2","zeta2","eta2","theta2","iota2","kappa2","lambda2","mu2","nu2","xi2","omicron2","pi2","rho2","sigma2","tau2","upsilon2","phi2","chi2","psi2","omega2"].map((v,i)=>`${String(i).padStart(3,"0")}-${v}-${btoa(v+Math.random().toString(36).slice(2))}`).join("|"); console.log(wrapLine);
Overlay token types for debugging tokenization rules.
api.showTokens();
Navigation & Scrolling
api.goto(lineNumber: number, opts?: { behavior?: 'auto'|'smooth', offset?: number })
Scrolls the view so that lineNumber is visible. If the line is inside a folded region, the fold summary is used as the anchor. The optional offset (defaults to searchOffsetPx) reserves space above.
// Simple task timer
class TaskTimer {
constructor(){ this.active=null; this.log=new Map(); }
start(name){
if(this.active) throw new Error(`Already timing ${this.active.name}`);
this.active={ name, at: performance.now() };
}
stop(){
if(!this.active) return;
const ms=performance.now()-this.active.at;
this.log.set(this.active.name,(this.log.get(this.active.name)||0)+ms);
this.active=null;
}
reset(){ this.active=null; this.log.clear(); }
top(n=5){ return [...this.log.entries()].sort((a,b)=>b[1]-a[1]).slice(0,n).map(([name,ms],i)=>`${String(i+1).padStart(2,"0")} ${name} ${ms.toFixed(1)}ms`); }
}
const sleep = ms => new Promise(r=>setTimeout(r,ms));
(async () => {
const tt = new TaskTimer();
for (const [name,wait] of [["build",120],["lint",75],["test",180],["deploy",90]]){
tt.start(name);
await sleep(wait + Math.random()*50);
tt.stop();
}
console.log("== Task report =="); for (const line of tt.top(4)) console.log(line);
})();
// Quick error demo (double start should throw)
try { const x=new TaskTimer(); x.start("A"); x.start("B"); }
catch (e) { console.warn("Expected error:", e.message); }
console.log("Demo done.");
api.scrollUp(lines = 1): number api.scrollDown(lines = 1): number
Scrolls up/down by a number of visual lines. Returns the new scrollTop.
// Simple task timer
class TaskTimer {
constructor(){ this.active=null; this.log=new Map(); }
start(name){
if(this.active) throw new Error(`Already timing ${this.active.name}`);
this.active={ name, at: performance.now() };
}
stop(){
if(!this.active) return;
const ms=performance.now()-this.active.at;
this.log.set(this.active.name,(this.log.get(this.active.name)||0)+ms);
this.active=null;
}
reset(){ this.active=null; this.log.clear(); }
top(n=5){ return [...this.log.entries()].sort((a,b)=>b[1]-a[1]).slice(0,n).map(([name,ms],i)=>`${String(i+1).padStart(2,"0")} ${name} ${ms.toFixed(1)}ms`); }
}
const sleep = ms => new Promise(r=>setTimeout(r,ms));
(async () => {
const tt = new TaskTimer();
for (const [name,wait] of [["build",120],["lint",75],["test",180],["deploy",90]]){
tt.start(name);
await sleep(wait + Math.random()*50);
tt.stop();
}
console.log("== Task report =="); for (const line of tt.top(4)) console.log(line);
})();
// Quick error demo (double start should throw)
try { const x=new TaskTimer(); x.start("A"); x.start("B"); }
catch (e) { console.warn("Expected error:", e.message); }
console.log("Demo done.");
api.lockScroll(state = true)
Temporarily disables scrolling inside the widget (useful for modal interactions).
api.lockScroll();
Rule & Line Numbers
api.showRuler(on: boolean) api.toggleRuler()
Show/hide the column ruler overlay.
api.toggleRuler();
api.setRulerPosition(position: 'top' | 'bottom')
Position of the ruler overlay.
api.setRulerPosition('bottom');
api.setRulerStyle(style: 'tens' | 'full')
Changes how the ruler renders: tens shows ticks every 10 columns, full renders a number for each column.
Notes:
The ruler must be visible to have an effect. Use showRuler(true) or toggleRuler().
function test() {
const grid = [];
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 4; j++) {
grid.push(`${i},${j}`)
};
}
console.log(grid.join(' '));
}
Search API
api.search(query: string, options?: { caseSensitive?: boolean, regex?: boolean, wholeWord?: boolean, inline?: boolean, inlineHL?: boolean, viewOffsetPx?: number }): number
Searches within the current text. Returns the number of matching lines. When inline is true, individual match fragments are highlighted inside lines (and optionally in the highlighted view with inlineHL).
Returns geometry and metadata suitable for aligning tooltips/popovers with the current hit. When preferInline is true, the inline fragment is used if available; otherwise the whole line anchor is used.
Clears all search highlights and resets the search cursor.
api.clearSearch();
Marks & Focus
api.mark(spec: string | number[])
Marks a set of lines. Accepts a comma-separated string of numbers and ranges like "1,3,10-15", or an array of line numbers. Passing a non-string, non-array clears the override.
api.mark("1,3,10-15"); // string spec
api.mark([2,4,6]); // numeric form
function test() {
const grid = [];
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 4; j++) {
grid.push(`${i},${j}`)
};
}
console.log(grid.join(' '));
}
Code Folding
api.isFoldable(line: number): boolean
Check if a row is foldable. Return true if the line can start a fold.
if (api.isFoldable(40)) {
api.toggleFoldAt(40);
}
api.getFoldableLines(): number[]
Builds a fold map either from braces (JS/CSS/etc.) or from HTML tag structure.
api.getFoldableLines();
api.foldAt(line: number): boolean
Collapses (folds) the region that starts at line. The editor hides all lines in that region except the header. Return true if a fold was performed.
api.foldAt(40);
api.unfoldAt(line: number): boolean
Expands the folded region that starts at line (i.e., makes its hidden lines visible again). Return true if an unfold occurred.
api.unfoldAt(40);
api.toggleFoldAt(line: number): boolean
Convenience method that folds if the region at line is currently open, or unfolds it if it’s currently folded.
api.toggleFoldAt(40);
api.unfoldAll(): void
Expands every folded region in the document, restoring full visibility.
api.unfoldAll();
api.rebuildFoldMap(): void
Recomputes the internal fold map from the current document text and folding rules (e.g., indentation, brackets, language parser).
api.rebuildFoldMap();
function test() {
const grid = [];
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 4; j++) {
grid.push(`${i},${j}`)
};
}
console.log(grid.join(' '));
}
Collapsed lines indicator.
When a region is collapsed, PWAxcode replaces it with a compact summary row that shows how many lines are hidden (e.g., “7 lines collapsed”). Click the summary (or the caret in the gutter) to expand; click again to collapse. The summary keeps line numbering consistent and can be focused and toggled via keyboard (Enter / Space).
Popovers & Toasts
api.toast(message: string, opts?: { type?: 'info'|'success'|'warning'|'error', ms?: number })
Opens a popover anchored either to a named anchor ('container' or the current 'search' hit), a CSS selector, a specific element, or an absolute page-rect. The popover is accessible (role="dialog") and stacked above the widget.
Applies a saved state. By default it merges options, updates content, and replays the active search; it can also enter/exit compressed/fullscreen if permitted. Returns true on success.
Also supported (stored as options, typically read at init or by specific methods): footerControls, footerAlign, toastPosition, toastMax, copyToastMs, autoIndent, searchOffsetPx, fontSize, fontLineHeight, fontMin, fontMax, fontStep, typingCPS, autoFormatAfterTyped, fullscreen, compressed, markSpec, dedent, locale, translations.
Keyboard friendly. You can move around with Tab/Shift+Tab. When you see a collapsed section (it shows “… lines collapsed”), select it and press Enter or Space to expand or collapse.
Clear labels. Buttons and controls are announced with meaningful names for screen readers.
Predictable focus. After collapsing, focus stays on the summary row; after expanding, focus returns to the header. Press Esc to close popovers and return focus to the button that opened them.
Readable at any size. Use the Zoom controls (A+/A–) or your browser zoom to increase text. Line numbers and the ruler can be shown or hidden from the view controls.
Reduced motion. If animations bother you, enable “Reduce motion” in your system settings—PWAxcode follows that preference.
Good contrast. Switch theme (Light/Dark, etc.) from the theme menu to improve readability.
Performance Tips
Working with very long files? Turn off “HL” (syntax highlighting) from the toolbar and re-enable it only when needed.
Collapse what you don’t need. Fold large sections to keep scrolling smooth.
Keep overlays light. Close popovers you’re not using and disable token/diagnostic overlays when they’re not necessary.
Zoom sensibly. Extremely large zoom levels can make big files feel slower; try a moderate zoom.
Search smoothly. Start a search, then use “Next/Previous” to move between results; wait for the page to settle before starting another search.
When in doubt, download. If your browser struggles with a huge file, download the text and open it in your desktop editor.
Troubleshooting
The floating toolbar doesn’t appear. Open the menu (⋯) and enable “Floating toolbar.” If you’re in fullscreen or “compressed” mode, exit it and try again. Make sure the page isn’t zoomed so far that the bar is off-screen—scroll a little to reveal it.
I can’t expand a collapsed section. Click the “… lines collapsed” row (or the caret in the gutter) and press Enter or Space. If it still won’t open, click once to select it and press Enter again. As a last resort, use “Unfold all” from the folding menu.
“Go to line” lands in the wrong place. If the target line is inside a collapsed block, the view scrolls to that block’s header first. Expand the block, then try “Go to line” again.
Downloaded file has the wrong name. Set a title at the top of the widget (if available) before downloading, or rename the file from your browser’s download shelf.
The ruler doesn’t show or won’t change style. Turn on “Ruler” from the view controls, then choose its style (“Tens” or “Full”) and position (“Top” or “Bottom”).
Popovers look out of place. Scroll the target into view and open the popover again. Very high zoom or narrow windows can push popovers off-screen; reduce zoom slightly or widen the window.
Fullscreen won’t start. Your browser or site may block fullscreen. Allow it if prompted, or try clicking the fullscreen button again after interacting with the page.
Copy to clipboard doesn’t work. Some browsers require a user gesture and a secure page (HTTPS). Use Ctrl/Cmd+C after selecting the text; on mobile, tap-and-hold then choose Copy.
Scrolling feels “stuck.” Check if a dialog or popover is open; press Esc to close it. If the page still won’t scroll, click inside the code area and try again.
Search finds nothing but the word is on the page. Check the search options (case sensitivity, whole-word, or regex) and try again. Clear previous highlights before starting a new search.
Highlight boxes look slightly misaligned. After changing font size or line wrapping, toggle wrap off/on or briefly resize the window to let overlays realign.
Line numbers start from an unexpected value. Look for the line-number settings in the view controls and reset the starting number to 1.