If I understand correctly, I think your problem is that the Bio field isn't a fully functional DOM where your CSS rules can be interpreted. They have to be inlined. You can still manage a modicum of abstraction and composability by declaring your CSS as properties of a JS object, and then building your HTML using factory functions. I lifted and adapted this from others in the House of Mod, but it would basically look like: // CSS =======================================
const defaultThemeColor1 = '#66806a'; const css = { tb: { width: '100%', margin: '0 auto', 'border-collapse': 'collapse', 'font-size': '12px', }, p: {}, a: {}, img: {}, h1: {}, h2: {}, h3: {}, h4: {}, h5: {}, th: { 'border-bottom': `1px solid #000000`, 'font-weight': `bold`, 'text-align': `center`, 'line-height': `22px` }, tr: {}, td: { padding: '4px', 'min-width': '10px' }, code: {}, pre: { 'color': 'dimgray', 'background': 'transparent', 'border': 'none', 'white-space': 'pre-wrap', 'font-family': 'Inconsolata, Consolas, monospace' }, div: { 'background-color': '#000000', 'overflow': `hidden` }, divContainer: { 'background-color': '#000000', 'overflow': `hidden`, width: '100%', border: 'none' }, rounded: { 'border-radius': `10px`, 'border': `2px solid #000000`, }, //... }; You can see I establish a default color (I would probably do more with defaults here, so that they could be reused throughout the CSS), and then I declare "rules" for basic structural tags and for "classes" (like "rounded"). Then you'd have an html factory like: const combineCSS = (origCSS = {}, ...assignCSS) => { return Object.assign({}, origCSS, assignCSS.reduce((m, v) => { return Object.assign(m, v || {}); }, {})); }; const assembleCSS = (css) => { return `"${Object.keys(css).map((key) => { return `${key}:${css[key]};` }).join('')}"`; }; // HTML ======================================= const html = { div: (content, ...CSS) => `<div style=${assembleCSS(combineCSS(css.div, ...CSS))}>${content}</div>`, h1: (content, ...CSS) => `<h1 style=${assembleCSS(combineCSS(css.h1, ...CSS))}>${content}</h1>`, h2: (content, ...CSS) => `<h2 style=${assembleCSS(combineCSS(css.h2, ...CSS))}>${content}</h2>`, h3: (content, ...CSS) => `<h3 style=${assembleCSS(combineCSS(css.h3, ...CSS))}>${content}</h3>`, h4: (content, ...CSS) => `<h4 style=${assembleCSS(combineCSS(css.h4, ...CSS))}>${content}</h4>`, h5: (content, ...CSS) => `<h5 style=${assembleCSS(combineCSS(css.h5, ...CSS))}>${content}</h5>`, p: (content, ...CSS) => `<p style=${assembleCSS(combineCSS(css.p, ...CSS))}>${content}</p>`, table: (content, ...CSS) => `<table style=${assembleCSS(combineCSS(css.tb, ...CSS))}>${content}</table>`, th: (content, ...CSS) => `<th style=${assembleCSS(combineCSS(css.th, ...CSS))}>${content}</th>`, tr: (content, ...CSS) => `<tr style=${assembleCSS(combineCSS(css.tr, ...CSS))}>${content}</tr>`, td: (content, ...CSS) => `<td style=${assembleCSS(combineCSS(css.td, ...CSS))}>${content}</td>`, td2: (content, ...CSS) => `<td colspan="2" style=${assembleCSS(combineCSS(css.td, ...CSS))}>${content}</td>`, code: (content, ...CSS) => `<code style=${assembleCSS(combineCSS(css.code, ...CSS))}>${content}</code>`, pre: (content, ...CSS) => `<pre style=${assembleCSS(combineCSS(css.pre, ...CSS))}>${content}</pre>`, span: (content, ...CSS) => `<span style=${assembleCSS(combineCSS(css.span, ...CSS))}>${content}</span>`, a: (content, link, ...CSS) => `<a href="${link}" style=${assembleCSS(combineCSS(css.a, ...CSS))}>${content}</a>`, img: (content, altText, ...CSS) => `<img src="${content}" alt="${altText}" style=${assembleCSS(combineCSS(css.img, ...CSS))}>`, tip: (content, tipText, ...CSS) => `<span class="showtip tipsy-n-right" title="${HE(HE(tipText))}"style=${assembleCSS(combineCSS(css.span, ...CSS))}>${content}</span>` }; Where the HE() function is Aaron's HTML escape function: // HTML Escaping function const HE = (() => { const esRE = (s) => s.replace(/(\\|\/|\[|\]|\(|\)|\{|\}|\?|\+|\*|\||\.|\^|\$)/g, '\\$1'); const e = (s) => `&${s};`; const entities = { '<': e('lt'), '>': e('gt'), "'": e('#39'), '@': e('#64'), '{': e('#123'), '|': e('#124'), '}': e('#125'), '[': e('#91'), ']': e('#93'), '"': e('quot') }; const re = new RegExp(`(${Object.keys(entities).map(esRE).join('|')})`, 'g'); return (s) => s.replace(re, (c) => (entities[c] || c)); })(); To use all of that, you'd build your html as a series of nested tags: let output = html.div(html.h1('Header Content') + html.div('This is the main content'), css.divContainer, css.rounded, { border: '2px red solid'}); You can pass established css rule objects or new ad hoc objects. Because the html factory uses the combineCSS function, the last CSS rules applied get written to the style object last, meaning they act just like more specific CSS rules taking precedence over less specific references. And the assembleCSS function turns the style object into actual inline css rules for the html element you want to style. Your CSS is still reusable even though you are building your presentation components individually and rendering the styles individuall/inline.