Purpose
Provide a direct, reusable method for investigating the Key Highlights table on Madison Funds detail pages, including its structural selectors, raw header-row HTML, headers, and normalized row contents.
When to Use
Use for any Madison Funds detail page under /funds/{fund-slug}/ or /etfs/{etf-slug}/ when the caller needs the Key Highlights table DOM structure, raw header markup, or displayed data.
Workflow
- Navigate directly to the supplied detail URL:
https://madisonfunds.com/funds/{fund-slug}/orhttps://madisonfunds.com/etfs/{etf-slug}/. If only a display name is available, first use the fund or ETF index page to select the matching detail-page href; do not invent a slug. - On the loaded detail page, run this single evaluator. It finds the
h4titled “Key Highlights”, follows its nearest.table-headerto the next sibling wrapper, locates the table, returns the raw HTML of its final header row, and extracts normalized headers and body rows:
(() => {
const clean = (value) => (value || "").replace(/\\s+/g, " ").trim();
const heading = [...document.querySelectorAll("h4")].find((el) =>
/^key highlights$/i.test(clean(el.textContent)),
);
if (!heading) {
return {
found: false,
heading: null,
tableSelector: null,
rawHeaderHTML: null,
headers: [],
rows: [],
};
}
const header = heading.closest(".table-header");
const wrapper = header?.nextElementSibling || null;
const table = wrapper?.querySelector("table") || null;
if (!table) {
return {
found: false,
heading: clean(heading.textContent),
tableSelector: null,
rawHeaderHTML: null,
headers: [],
rows: [],
};
}
const headerRow = table.querySelector("thead tr:last-child");
const headers = [...(headerRow?.querySelectorAll("th, td") || [])].map((cell) =>
clean(cell.textContent),
);
const rows = [...table.querySelectorAll("tbody tr")]
.map((row) =>
[...row.querySelectorAll("th, td")].map((cell) => clean(cell.textContent)),
)
.filter((row) => row.length > 0);
return {
found: true,
heading: clean(heading.textContent),
tableSelector:
"h4[text=Key Highlights] -> closest(.table-header) -> nextElementSibling table",
wrapperTag: wrapper.tagName,
wrapperClass: wrapper.className,
tableClass: table.className,
rawHeaderHTML: headerRow ? headerRow.outerHTML : null,
headers,
rows,
};
})();Site-Specific Gotchas
- The section title is an
h4, not a dedicated ID; identify it by normalized text equal toKey Highlights. - The table is not a direct sibling of the
h4. The reliable path is theh4’s closest.table-header, then itsnextElementSibling, thentablewithin that wrapper. - The raw header row is the final
thead tr; return itsouterHTMLasrawHeaderHTMLwithout modifying the markup. - Extract header and body data from both
thandtd, because row-label cells may use either element. - Normalize whitespace when comparing headings or returning text values; rendered markup can contain line breaks and indentation. The raw HTML remains unnormalized.
- The same structural pattern is used on observed fund and ETF detail pages, but a page may omit the section; always return the explicit
found: falseshape when absent.
Expected Output
The evaluator returns an object with found, heading, structural class/tag metadata, tableSelector, rawHeaderHTML, headers, and rows. rawHeaderHTML is the complete DOM outerHTML of the table’s final header row. rows is an array of arrays containing visible, whitespace-normalized cell text in DOM order.