There is a Window called “caption” in calculation & fiel where you can add some information. That info is written below the main topic or calculation. You allready tried to minimize that by offering a much smaller text. But it would be way better if people like me could use the “caption” field and the option to hide the text behind a small “info” button like that
. Position of that should be behind the main topic/calculation in the right top corner … like m². By tapping or mouse over effect on the info, the text will appear and the whole calc is way easier to read. Looking forward to see it. Dimitri
Hi there, @user23793 ![]()
Interesting idea, thanks for sharing! If more users support this request, we’ll try to think it over in the future.
As for now, our devs will be happy to create a custom solution for you. I’ve forwarded your request to them and let you know once it’s done ![]()
Hi there, @user23793 ![]()
This code should be added to the Custom JS field on the Settings tab of your widget’s settings:
const INFO_LIST = ['Eigenkapital', 'Monatliche Kosten ⁉️'];
function listener(selector, callback) {
const target = document.querySelector(selector);
if (target) return callback(target);
const observer = new MutationObserver(() => {
const node = document.querySelector(selector);
if (node) {
observer.disconnect();
callback(node);
}
});
observer.observe(document.body, { childList: true, subtree: true });
}
function normalizedString(str) {
return str.toLowerCase().trim();
}
function createElement(tag, options = {}) {
return Object.assign(document.createElement(tag), options);
}
function createInfo(size) {
const container = createElement('div', {
className: 'result-info-container',
style: `
display: flex;
align-items: center;
justify-content: center;
opacity: 0.7;
font-size: ${Math.floor((size * 2) / 3)}px;
width: ${size}px;
height: ${size}px;
border: 1px solid rgb(17, 17, 17);
border-radius: 50%;
`
});
const block = createElement('div', {
className: 'result-info',
textContent: 'i'
});
container.appendChild(block);
return container;
}
function mapResultBlocks(container) {
const resultList = container.querySelectorAll('[class^="result"]');
const map = new Map();
for (const block of resultList) {
const isSecondary = block.className.includes('secondary');
const labelWrapper = (() => {
if (isSecondary) {
return block.querySelector(
'[class*="result-secondary__SecondaryLabel-sc"]'
);
}
return block;
})();
if (!labelWrapper) continue;
const label = labelWrapper.firstElementChild;
const caption = labelWrapper.lastElementChild;
const labelText = label?.textContent;
if (!labelText) continue;
const value = (() => {
if (isSecondary) {
return block.querySelector('[class*="result-secondary__Value-sc"]');
}
return block.querySelector('[class*="result-primary__Value-sc"]');
})();
map.set(normalizedString(labelText), {
label,
container: block,
caption: label === caption ? null : caption,
value,
isSecondary
});
}
return map;
}
function attachHoverBehavior(value, infoSize) {
let isHovering = false;
let isTouched = false;
const { value: valueNode, caption, container, isSecondary } = value;
if (!caption || !valueNode) return;
const info = createInfo(infoSize);
valueNode.appendChild(info);
valueNode.style.display = 'flex';
valueNode.style.alignItems = 'center';
if (isSecondary) {
const animatedValue = valueNode.querySelector(
'[class*="animated-number__Content-sc"]'
);
const hiddenValue = valueNode.querySelector(
'[class*="result-secondary__HiddenValue-sc"]'
);
if (animatedValue) animatedValue.style.position = 'relative';
if (hiddenValue) hiddenValue.style.display = 'none';
valueNode.style.minWidth =
parseInt(window.getComputedStyle(valueNode).minWidth || '0') +
infoSize +
'px';
valueNode.style.justifyContent = 'end';
}
container.style.position = 'relative';
container.style.overflow = 'unset';
caption.style.cssText = `
margin-top: 0;
display: none;
position: absolute;
top: 0;
left: 0;
width: 100%;
background-color: #fff;
z-index: 2;
opacity: 1;
padding: 8px 12px;
border-radius: 4px;
box-shadow: 0px 2px 8px 0px #00000040;
`;
function show() {
isHovering = true;
caption.style.display = 'block';
}
function hide() {
isHovering = false;
setTimeout(() => {
if (!isHovering) caption.style.display = 'none';
}, 100);
}
valueNode.addEventListener('mouseenter', show);
valueNode.addEventListener('mouseleave', hide);
caption.addEventListener('mouseenter', show);
caption.addEventListener('mouseleave', hide);
valueNode.addEventListener('touchstart', (e) => {
e.stopPropagation();
isTouched = !isTouched;
if (isTouched) {
show();
} else {
hide();
}
});
document.addEventListener('touchstart', (e) => {
if (!valueNode.contains(e.target) && !caption.contains(e.target)) {
isTouched = false;
hide();
}
});
}
listener('[class*="results__Container-sc"]', (container) => {
const mappedBlocks = mapResultBlocks(container);
INFO_LIST.forEach((title) => {
const value = mappedBlocks.get(normalizedString(title));
if (!value || !value.value) return;
const fontSize = parseInt(
window.getComputedStyle(value.value).fontSize || '14'
);
const infoSize = Math.floor(fontSize / 2);
attachHoverBehavior(value, infoSize);
});
});
In the 1st line, you should add the calculation names where the captions should appear on hover:
Please try it out and let me know if you like the result ![]()
Hi,
it works almost perfectly. Small things to adjust…
- the hover Info should be connected to the title, not to the result.
- if using the view of „secondary result“, the i hover button is way to small.
- works only in the „calculations“ not in „ fields“
But in general it’s a cool calc!!!
Dimitri Geizenräder
Otto-Brenner-Strasse 86
D-45549 Sprockhövel
phone 49 (0)176 22 36 11 83
von unterwegs gesendet
Hi there, @user23793 ![]()
Thank you for the feedback!
I’ll discuss with the devs if it’s possible to adjust the first 3 points you’ve mentioned
A post was split to a new topic: Dynamic field caption
Hi there, @user23793 ![]()
Here is a final solution with the requested adjustments:
const WIDGET_SELECTOR = '.elfsight-app-8fc0c5c7-3987-491f-a48b-1703f4ba3566';
const INFO_LIST = [
'Zu versteuerndes Einkommen',
'a) Zinsen + Tilgung p.a.',
'Eigenkapital'
];
function listener(selector, callback) {
const firstTarget = document.querySelector(selector);
if (firstTarget) {
return callback(firstTarget);
}
const observer = new MutationObserver((_, observer) => {
const targetNode = document.querySelector(selector);
if (targetNode) {
observer.disconnect();
callback(targetNode);
}
});
observer.observe(document.body, { childList: true, subtree: true });
}
function createElement(tag, options) {
return Object.assign(document.createElement(tag), options);
}
function normalizedString(string) {
return string.replace(/\s+/g, '').toLowerCase();
}
function installStyles() {
return document.head.appendChild(
createElement('style', {
innerHTML: `
.result-info-container + .tooltip-wrapper {
display: none;
}
.result-info-container:hover + .tooltip-wrapper,
.result-info-container:focus + .tooltip-wrapper,
.result-info-container:active + .tooltip-wrapper {
display: block;
}
.result-info-container + .tooltip-wrapper:hover,
.result-info-container + .tooltip-wrapper:focus,
.result-info-container + .tooltip-wrapper:active {
display: block;
}
`
})
);
}
function createInfo(size) {
const container = createElement('button', {
tabindex: '0',
className: 'result-info-container',
style: `
display: flex;
align-items: center;
justify-content: center;
opacity: 0.7;
font-size: ${Math.floor((size * 2) / 3)}px;
width: ${size}px;
height: ${size}px;
border: 1px solid rgb(17, 17, 17);
border-radius: 50%;
margin-left: 8px;
background: transparent;
`
});
const block = createElement('div', {
className: 'result-info',
textContent: 'i'
});
container.appendChild(block);
return container;
}
function getDescriptionSelector(type) {
return {
primary: '[class*="result-primary__PrimaryContainer-sc"] > :nth-child(3)',
secondary: '[class*="result-secondary__SecondaryLabel-sc"] > :nth-child(2)',
field: '[class*="FormFieldLayout__Hint-sc"]'
}[type];
}
function getDescription({ type, node }) {
const selector = getDescriptionSelector(type);
if (!selector) {
return;
}
if (type === 'field') {
return node
.closest('[class*="FormFieldLayout__Element-sc"]')
?.querySelector(selector);
}
return node.parentNode.querySelector(selector);
}
const selector = `${WIDGET_SELECTOR} [class*="widget__Layout-sc"]`;
listener(selector, (container) => {
const formLabels = Array.from(
container.querySelectorAll(
'[class*="form__Container-sc"] [class*="Label-sc"]'
)
).map((node) => ({ type: 'field', node }));
const primaryLabel = Array.from(
container.querySelectorAll(
'[class*="result-primary__PrimaryContainer-sc"] > div'
)
).map((node) => ({ type: 'primary', node }));
const secondaryLabel = Array.from(
container.querySelectorAll(
'[class*="result-secondary__SecondaryLabel-sc"] > div'
)
).map((node) => ({ type: 'secondary', node }));
const targetBlocks = [
...formLabels,
...secondaryLabel,
...primaryLabel
].filter(({ node }) =>
INFO_LIST.some(
(label) => normalizedString(label) === normalizedString(node.textContent)
)
);
installStyles();
targetBlocks.forEach(({ type, node }) => {
const description = getDescription({ type, node });
console.log(description);
if (!description) {
return;
}
const size = parseInt(window.getComputedStyle(node).fontSize);
const infoBlock = createInfo(size);
node.appendChild(infoBlock);
node.style.display = 'inline-flex';
node.style.alignItems = 'center';
description.style.cssText = `
opacity: 1;
padding: 8px 16px;
margin-top: ${(size + 8) * (type === 'field' ? 2 : 1)}px;
background-color: #fff;
box-shadow: 0px 2px 8px 0px #00000040;
border-radius: 8px;
`;
const tooltipWrapper = createElement('div', {
className: 'tooltip-wrapper',
style: `
position: absolute;
top: 0;
left: 0;
width: 100%;
z-index: 2;
`
});
tooltipWrapper.appendChild(description);
node.appendChild(tooltipWrapper);
const container = node.parentNode.closest('[class*="Container-sc"]');
if (!container) {
return;
}
container.style.position = 'relative';
container.style.overflow = 'unset';
});
});
Please try it out and let me know how it worked ![]()
Hello max,
sorry for late answering…holidays. I tried and so far ist allmost perfect, check yourself … comlicated calc reduced to only 4 sliders … great tool, thank you! Dein U | VILLAGEU
Great, thank you so much for the feedback!
You said it’s almost perfect — is there anything specific in the widget’s design you’d like to tweak?
If so, just let us know the details, and we’ll do our best to make it happen ![]()

