Integration & Embedding Guide
A comprehensive developer reference for embedding, configuring, customizing, and integrating data feeds for professional VNInvestCharts.
Widget Embedding Methods
The widget supports three independent embedding architectures depending on your host app’s CSS control and security requirements:
React Component
Embed the component directly into the React DOM tree. Shares memory and Context with the Host Application.
Shadow DOM Isolation
Wrap the widget in an independent Shadow Root. Completely isolates widget CSS from the Host Application.
Iframe PostMessage SDK
Completely isolates both JavaScript and CSS through a secure cross-domain iframe.
Standard React Component Embedding
Direct component embedding into the React application tree.
Import Component and Styles
import { VNInvestCharts, widgetMessagesVi, widgetMessagesEn } from "vninvestcharts-widget";
// Import stylesheet hỗ trợ giao diện đầy đủ (CSS Modules)
import "vninvestcharts-widget/dist/index.css";Usage in Component
function ChartContainer() {
return (
<div style={{ width: "100%", height: "600px", position: "relative" }}>
<VNInvestCharts
symbol="VCB"
timeframe="1D"
theme="dark"
locale="vi"
messages={widgetMessagesVi}
drawingUiEnabled={true}
/>
</div>
);
}Shadow DOM Isolation Embedding
To prevent chart CSS from breaking the Host App layout (or vice versa), you can embed the widget inside a Shadow Root.
Click-Outside & Dropdown Event Patch
When inside Shadow DOM, click events are hidden from the host (e.target points to the shadow host itself). To ensure dropdowns, symbol search, and drawing toolbar work correctly:
- The library uses e.composedPath()[0] instead of e.target to correctly identify the clicked element inside Shadow DOM.
- Pass the Shadow Root context to the widget via the global variable window.__vnscShadowRoot or the shadowRoot property.
Initialization Configuration (IIFE Entry)
// Tạo phần tử chứa widget
const hostContainer = document.getElementById("chart-widget-host");
const shadowRoot = hostContainer.attachShadow({ mode: "open" });
// 1. Inject thẻ CSS trực tiếp vào bên trong Shadow Root
const link = document.createElement("link");
link.rel = "stylesheet";
link.href = "vninvestcharts-widget/dist/index.css";
shadowRoot.appendChild(link);
// 2. Tạo điểm gắn kết React inside Shadow DOM
const mountPoint = document.createElement("div");
mountPoint.id = "vnsc-shadow-root-mount";
shadowRoot.appendChild(mountPoint);
// 3. Khai báo biến toàn cục để thông báo ranh giới Shadow Root
window.__vnscShadowRoot = shadowRoot;
// 4. Khởi tạo Widget
window.VNInvestCharts.mount(mountPoint, {
symbol: "VCB",
timeframe: "1D",
theme: "dark",
locale: "vi",
shadowRoot: shadowRoot // Cung cấp shadowRoot trực tiếp cho event listeners
});Iframe SDK Embedding (PostMessage Bridge)
This method completely isolates the Widget source code from the Host App. Suitable for embedding charts across different domains.
Step 1: Create iframe.html on Widget Server
The iframe.html file loads the dist/iframe/vnbrokerchart.iframe.js bundle and automatically listens for control commands:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>VNInvestCharts Iframe Node</title>
<link rel="stylesheet" href="injected.css">
<style>
html, body, #root { width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden; }
</style>
</head>
<body>
<div id="root"></div>
<script src="vnbrokerchart.iframe.js"></script>
</body>
</html>Step 2: Use Host SDK in the Host App
The Host App uses the WidgetController class to communicate asynchronously via window.postMessage:
import { WidgetController } from "vninvestcharts-widget/iframe";
// 1. Tạo controller trỏ tới thẻ iframe
const iframeElement = document.getElementById("my-chart-iframe") as HTMLIFrameElement;
const controller = new WidgetController({
iframe: iframeElement,
targetOrigin: "https://chart.domain.com", // Bảo mật: Chỉ định rõ domain nguồn của iframe
allowAnyOrigin: false // Bắt buộc đặt false trên production để tránh tin tặc giả mạo lệnh
});
// 2. Lắng nghe các sự kiện gửi ra từ biểu đồ
controller.on("symbolChange", (data) => {
console.log("Người dùng đổi mã trên biểu đồ sang:", data.symbol);
});
controller.on("drawingsChange", (data) => {
console.log("Danh sách hình vẽ kỹ thuật vừa cập nhật:", data.drawings);
});
// 3. Gửi lệnh điều khiển vào biểu đồ (không cần re-render iframe)
async function updateChartState() {
// Đổi mã
await controller.setSymbol("FPT");
// Đổi khung thời gian
await controller.setTimeframe("15m");
// Áp dụng chỉ báo
await controller.addIndicator("StrengthRelative", { period: 14 });
}Data Adapter Integration & Boundary Lock Mechanism
To load candlestick data for the embedded chart, you need to provide a StockDataAdapter. The v3.0 upgrade improves the backfill mechanism to completely eliminate infinite network request loops.
Backfill Mechanism
- When the chart is panned left or right for zoom/pan, the useWidgetDataBackfill hook calculates whether the visible time range is missing candles.
- If candles are missing, the system triggers additional loading via fetchBarsBefore (backward) or fetchBarsInRange (forward).
Important Notes When Writing an Adapter
When your API has exhausted historical or real-time data (reached the symbol’s boundary), the adapter MUST return an empty candle array or report boundary-exhausted status.
export const mySecureAdapter: StockDataAdapter = {
fetchBarsBefore: async (symbol, timeframe, beforeDate, limit) => {
const bars = await api.getBars({ symbol, timeframe, before: beforeDate.getTime(), limit });
// Dữ liệu trống -> khóa biên lịch sử (tương tự [] hoặc boundary-exhausted)
// Hệ thống sẽ khóa biên trái và không bao giờ gọi lại trước mốc thời gian đó nữa.
return bars;
},
fetchBarsInRange: async (symbol, timeframe, fromDate, toDate) => {
const bars = await api.getBars({ symbol, timeframe, from: fromDate.getTime(), to: toDate.getTime() });
// Nạp theo mốc, nếu không có nến mới hơn, hệ thống sẽ khóa biên phải tại nến cuối cùng
return bars;
}
};Authentication & License Key Configuration
New security and licensing upgrades for the commercial distribution version:
PAT (Personal Access Token) Configuration for Data Adapter
For adapters requiring secure credentials like VNInvestDataAdapter, user tokens (PAT) should not be hardcoded but passed dynamically through an auth handler:
const authHandler = {
getPAT: () => localStorage.getItem("vninvest_pat_token") ?? "",
setPAT: (token: string) => localStorage.setItem("vninvest_pat_token", token)
};
// Sử dụng trong React Render
<VNInvestCharts
adapter={vninvestDataAdapter}
authHandler={authHandler}
// ... các cấu hình khác
/>Embedding License Verification (License Key)
The widget provides an embed license verification mechanism. When passing the licenseKey prop, the widget displays licensing information in the Settings panel and performs Domain Signature Validation:
<VNInvestCharts
licenseKey="vninvest-lic-xxxx-yyyy-zzzz"
// ...
/>The Licensing tab in the settings panel displays:
- License status (Active / Invalid).
- Authorized registered domain name.
- License expiration date.
Detailed Props Reference for v3.0
Detailed listing of all <VNInvestCharts> input props for configuration. Use the search bar to quickly locate props:
| Property | Type | Status | Description |
|---|---|---|---|
| symbol | string | Required | Stock symbol or coin code to display on the chart (e.g., FPT, HPG, BTCUSDT). |
| timeframe | string | Required | Default chart timeframe (e.g., 5m, 15m, 1h, 1d, 1w, 1M). |
| theme | "light" | "dark" | Default: dark | Chart color theme. |
| locale | "vi" | "en" | Default: vi | UI language and indicator annotation locale. |
| messages | Record<string, string> | Optional | Custom language dictionary overrides for the UI. |
| drawingUiEnabled | boolean | Default: false | Enable/Disable the left drawing toolbar. |
| showToolbar | boolean | Default: false | Show/Hide the drawing toolbar. |
| showHeader | boolean | Default: false | Show/Hide the top control bar (symbol, timeframe, indicators). |
| showFooter | boolean | Default: false | Show/Hide the bottom status information bar. |
| licenseKey | string | Optional | License key string to activate commercial features. |
| authHandler | WidgetAuthHandler | Optional | Handler for retrieving/storing the end user’s Personal Access Token (PAT). |
| shadowRoot | ShadowRoot | Optional | Outer Shadow Root boundary. Required when embedding in isolated Shadow DOM mode. |
| useWebGL | boolean | Default: false | Enable hardware acceleration via WebGL for heavy technical indicator rendering. |
| onError | (err: Error) => void | Optional | Receives data loading errors (e.g., 504 Timeout) for custom error display instead of crashing the UI. |