The GFS Design System is deployed as a static site on Cloudflare Pages. There is no traditional REST API backend, but every component is available via direct URL. This page documents three approaches for pulling design system components into other GFS tools: suitelets, dashboards, internal apps, and standalone HTML builds.
Source of truth: shared.css + tokens.json
Deploy target: Cloudflare Pages (auto-deploy on push)
CORS: Same-origin by default. Use iframe for cross-origin embeds.
Choose the approach that fits your context. Each has tradeoffs around isolation, styling control, and setup complexity.
Embed a full GFS page or a specific section by targeting a hash fragment. The iframe provides complete style isolation -- the host page's CSS cannot interfere with GFS components.
<!-- Embed the color palette section from snippets --> <iframe src="https://gfs-design-v9.pages.dev/snippets.html#s-colors" width="100%" height="400" style="border:1px solid #D9E1EA;" loading="lazy" title="GFS Color Palette" ></iframe> <!-- Embed the full components page --> <iframe src="https://gfs-design-v9.pages.dev/components.html" width="100%" height="800" style="border:none;" loading="lazy" title="GFS Components" ></iframe>
- Complete style isolation
- Zero setup -- one line of HTML
- Always shows latest deploy
- Works cross-origin
- No CSS customization from host
- Fixed height (no auto-resize without JS)
- Heavier page weight
- Scrollbar inside frame
window.addEventListener('message', e => { if(e.data.gfsHeight) document.getElementById('gfs-frame').style.height = e.data.gfsHeight + 'px'; });
Fetch a GFS page, extract a specific section by ID, and inject it into a target element. Requires the host page to load shared.css for proper styling. Best for same-origin tools or tools you control.
/**
* Pull a GFS section into the current page.
* Requires: <link rel="stylesheet" href="https://gfs-design-v9.pages.dev/shared.css">
*/
async function gfsEmbed(targetSelector, sourceUrl, sectionId) {
const res = await fetch(sourceUrl);
const html = await res.text();
const doc = new DOMParser().parseFromString(html, 'text/html');
const sec = doc.getElementById(sectionId);
if (sec) {
const target = document.querySelector(targetSelector);
// Clear and append extracted section safely
while (target.firstChild) target.removeChild(target.firstChild);
const imported = document.importNode(sec, true);
target.appendChild(imported);
} else {
console.warn('[GFS] Section not found:', sectionId);
}
}
// Usage:
gfsEmbed(
'#my-container',
'https://gfs-design-v9.pages.dev/snippets.html',
's-colors'
);
- Full CSS control from host
- No iframe overhead
- Can manipulate injected DOM
- Smooth integration with host layout
- Host must load shared.css
- Same-origin or CORS required
- Host CSS can conflict
- JS setup required
Open snippets.html and copy any component's HTML directly. This is the simplest approach for one-off builds where you want full control and no external dependencies at runtime.
1. Open https://gfs-design-v9.pages.dev/snippets.html 2. Find the component you need (buttons, badges, tables, etc.) 3. Click [COPY] on the snippet card 4. Paste into your HTML file 5. Ensure shared.css is loaded, or inline the relevant CSS variables
- Zero runtime dependency possible
- Works anywhere HTML works
- Can inline styles for email/PDF
- No fetch, no iframe, no JS
- Manual -- does not auto-update
- Must check for design system changes
- Copy drift if system evolves
Select a component type and variant below. The explorer generates a live preview and three output formats you can copy directly.
<button class="btn btn-primary">Primary Action</button>
Copy-ready HTML for the ten most commonly embedded GFS components. Each includes a live preview and the code to reproduce it.
NetSuite suitelets render HTML inside a sandboxed environment. The following patterns let you inject GFS brand components directly into suitelet output.
/**
* @NApiVersion 2.1
* @NScriptType Suitelet
*/
define(['N/ui/serverWidget'], function(serverWidget) {
function onRequest(context) {
var form = serverWidget.createForm({ title: 'GFS Branded Suitelet' });
var htmlField = form.addField({
id: 'custpage_gfs_html',
type: serverWidget.FieldType.INLINEHTML,
label: 'GFS Content'
});
htmlField.defaultValue = getGfsHtml();
context.response.writePage(form);
}
function getGfsHtml() {
return [
'<link rel="preconnect" href="https://fonts.googleapis.com">',
'<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;600;700&family=Inter:wght@400;600;700;800&display=swap" rel="stylesheet">',
'<link rel="stylesheet" href="https://gfs-design-v9.pages.dev/shared.css">',
'<style>',
' /* Override NetSuite sandbox defaults */',
' .gfs-suitelet { font-family: "Inter", sans-serif; color: #1F1F1F; }',
' .gfs-suitelet * { box-sizing: border-box; }',
'</style>',
'<div class="gfs-suitelet">',
' <!-- Your GFS content here -->',
'</div>'
].join('\n');
}
return { onRequest: onRequest };
});
<div class="gfs-suitelet">
<!-- GFS buttons work directly once shared.css is loaded -->
<button class="btn btn-primary" onclick="approveRecord()">Approve PO</button>
<button class="btn btn-secondary" onclick="history.back()">Back to List</button>
<!-- Status badges -->
<span class="badge badge-green">Approved</span>
<span class="badge badge-yellow">Pending Review</span>
<span class="badge badge-red">Rejected</span>
<!-- Data table -->
<table class="demo-table" style="width:100%;margin-top:16px;">
<thead><tr><th>Item</th><th>Qty</th><th>Rate</th><th>Amount</th></tr></thead>
<tbody>
<tr><td>Barrel Cheddar</td><td>40,000 lbs</td><td>$1.8450</td><td>$73,800</td></tr>
</tbody>
</table>
</div>
<!-- Full branded suitelet page wrapper -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;600;700&family=Inter:wght@400;600;700;800&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://gfs-design-v9.pages.dev/shared.css">
<style>
.gfs-suitelet { font-family:'Inter',sans-serif; color:#1F1F1F; max-width:1200px; margin:0 auto; padding:24px; }
.gfs-suitelet * { box-sizing:border-box; margin:0; padding:0; }
.gfs-suitelet .ns-header { background:#092F64; color:#fff; padding:16px 24px; display:flex; align-items:center; justify-content:space-between; margin-bottom:24px; }
.gfs-suitelet .ns-header h1 { font-size:15px; font-weight:700; letter-spacing:.04em; }
.gfs-suitelet .ns-header .ns-meta { font-family:'IBM Plex Mono',monospace; font-size:10px; opacity:.7; letter-spacing:.06em; text-transform:uppercase; }
</style>
<div class="gfs-suitelet">
<div class="ns-header">
<h1>Global Food Solutions</h1>
<span class="ns-meta">Suitelet v1.0</span>
</div>
<div class="s">
<div class="s-head">
<span class="s-num">01</span>
<span class="s-title">Purchase Order Review</span>
<span class="s-meta">Approval Queue</span>
</div>
<div class="s-body" style="padding:24px;">
<!-- Your suitelet content here -->
</div>
</div>
</div>
NetSuite's INLINEHTML fields strip some CSS features. These patterns are confirmed to work:
Avoid in suitelets: position:fixed, position:sticky, CSS animations (@keyframes), backdrop-filter, ::before/::after pseudo-elements (inconsistent), CSS variables in older NS versions
Workaround: Replace CSS variables with hardcoded hex values if targeting older NetSuite environments. Use the embed codes from Section 04 which include inline hex fallbacks.
| PO # | Vendor | Amount | Status | Action |
|---|---|---|---|---|
| PO-2841 | Bongards | $42,180 | Pending | |
| PO-2842 | Dairy Farmers | $18,650 | Approved |
Every asset is served from the Cloudflare Pages edge. Use these URLs in any external tool, suitelet, or HTML build.
| Asset | URL | Type | Purpose |
|---|---|---|---|
| shared.css | https://gfs-design-v9.pages.dev/shared.css | CSS | Complete design tokens, component styles, brand DNA |
| print.css | https://gfs-design-v9.pages.dev/print.css | CSS | Print overrides (hides topbar, forces white bg) |
| favicon.svg | https://gfs-design-v9.pages.dev/favicon.svg | SVG | GFS favicon for browser tabs |
| tokens.json | https://gfs-design-v9.pages.dev/tokens.json | JSON | Machine-readable design tokens (colors, spacing, typography) |
| analytics.js | https://gfs-design-v9.pages.dev/analytics.js | JS | Cloudflare Web Analytics beacon |
<!-- Load the complete GFS design system in any HTML page --> <link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;600;700&family=Inter:opsz,wght@14..32,100..900&display=swap" rel="stylesheet"> <link rel="stylesheet" href="https://gfs-design-v9.pages.dev/shared.css"> <link rel="stylesheet" href="https://gfs-design-v9.pages.dev/print.css" media="print"> <link rel="icon" href="https://gfs-design-v9.pages.dev/favicon.svg" type="image/svg+xml">
// Fetch tokens programmatically for build tooling
fetch('https://gfs-design-v9.pages.dev/tokens.json')
.then(r => r.json())
.then(tokens => {
console.log('GFS Cobalt:', tokens.colors.primary.cobalt.value);
console.log('GFS Font:', tokens.typography.display.family);
console.log('Version:', tokens.version);
});
Understanding how Cloudflare Pages handles caching is critical when embedding GFS components in production tools.
Cache-Control: public, max-age=0, must-revalidate. This means browsers will always revalidate with the edge on each request, but the edge serves cached content instantly via ETag/If-None-Match.Result: Every page load checks for the latest version. If unchanged, Cloudflare returns 304 (not modified) in under 50ms. If a new deploy happened, the new version is served immediately.
Edge locations: 300+ Cloudflare PoPs worldwide. First request from a new PoP may take ~200ms; subsequent requests are served from edge cache.
Every new deploy to Cloudflare Pages generates a new content hash. There is no manual cache purge needed.
<!-- Option 1: Always latest (default -- no query string needed) --> <link rel="stylesheet" href="https://gfs-design-v9.pages.dev/shared.css"> <!-- Option 2: Force bypass browser cache with a deploy timestamp --> <link rel="stylesheet" href="https://gfs-design-v9.pages.dev/shared.css?v=20260518"> <!-- Option 3: Pin to a specific deploy hash (immutable) --> <link rel="stylesheet" href="https://abc123.gfs-design-v9.pages.dev/shared.css">
Cloudflare Pages assigns a unique subdomain to each deploy. Use this to pin a production tool to a known-good version while testing newer versions separately.
Production URL (always latest): https://gfs-design-v9.pages.dev/shared.css Deploy-pinned URL (immutable snapshot): https://<commit-hash>.gfs-design-v9.pages.dev/shared.css Branch preview URL: https://<branch-name>.gfs-design-v9.pages.dev/shared.css Example: Pin suitelets to a tested deploy https://a1b2c3d.gfs-design-v9.pages.dev/shared.css
Recommendation for dashboards: Use the production URL. Dashboards should always reflect the latest brand assets. The must-revalidate cache policy ensures updates are visible within seconds of deploy.
Recommendation for PDFs/exports: Inline the CSS. Do not depend on a remote URL for assets that must render offline.
| Version | Date | Breaking Changes |
|---|---|---|
| v10.0 | May 2026 | New token system, dark mode, 72 pages. Full rewrite from v8. |
| v8.x | 2025 | Legacy. Do not use for new builds. |