Replies
Hello,
Thank you for posting in our community!
I have been looking into your question, and what I can suggest is following the Getting Started topic in our documentation. On my side, I followed the “Using Vite CLI” approach, and after running the project, the grid was displayed successfully.
In order for the grid to be properly visualized, please make sure to import one of the themes as suggested in the topic. For example:
import 'igniteui-react-grids/grids/themes/light/bootstrap.css';
Additionally, to take advantage of the ready-to-use IgniteUI typography with already adjusted font family, weight, size, text transform, letter spacing, and line height, please make sure to add the ig-typography class to a root element, like the <body> tag.
<body class="ig-typography"> <div id="root"></div> <script type="module" src="/src/main.tsx"></script> </body>
Below is the sample setup for your reference. Please test it on your side and let me know if you need any further information on the matter.
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link rel="icon" type="image/svg+xml" href="/favicon.svg" /> <title>sample-demo</title> </head> <body class="ig-typography"> <div id="root"></div> <script type="module" src="/src/main.tsx"></script> </body> </html>
import './App.css'
import { IgrGrid, IgrColumn } from 'igniteui-react-grids';
import 'igniteui-react-grids/grids/themes/light/bootstrap.css';
function App() {
const data = [
{ name: "John", age: 30 },
{ name: "Jane", age: 25 },
{ name: "Bob", age: 35 }
];
return (
<>
<IgrGrid data={data} autoGenerate={false}>
<IgrColumn field="name" header="Name" dataType="string"></IgrColumn>
<IgrColumn field="age" header="Age" dataType="number"></IgrColumn>
</IgrGrid>
</>
)
}
export default App
Sincerely,
Riva Ivanova
Software Developer
Infragistics
Hello,
Thank you for posting in our community!
Based on the current implementation, the desired design can be achieved using a combination of NodeContentTemplate and custom CSS overrides.
The NodeContentTemplate option allows you to define a simplified custom HTML structure for each node. This is particularly useful because it enables you to attach your own CSS classes (e.g., for parent labels or pill-style child nodes) and then apply precise styling through CSS.
Apart from using the NodeContentTemplate, the rest of the visual customization should be handled by overriding the default igTree CSS classes. Here can be found a full list of all default igTree CSS classes and what they are used for.
Answers to your specific questions:
- Can the expand/collapse icons be repositioned and restyled?
Yes — this can be done entirely via CSS overrides (e.g., repositioning the expander and replacing icons with custom ones). - Is it possible to customize the node template or rendering structure?
Yes — the NodeContentTemplate option allows you to define custom HTML for the node content. - Can the indentation, spacing, and hierarchy presentation be modified through configuration or CSS?
These aspects are controlled via CSS and can be adjusted by overriding the default classes. - Would achieving the target design require custom templates, custom CSS, or a different Infragistics component?
A custom node template (via NodeContentTemplate) combined with CSS overrides is sufficient. This is the recommended approach for easier styling through custom classes. - Are there any limitations in IgniteUI 24.1.9 that we should be aware of?
There are no limitations relevant to this scenario that would prevent achieving the desired design.
In summary, the combination of NodeContentTemplate for structure and CSS overrides for styling provides enough flexibility to replicate the target layout without requiring a different component.
Below is a small example of how the igTree and its nodes can be styled. This aims to demonstrate a possible approach to achieving your desired design and may require additional adjustments.
<head>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" rel="stylesheet">
</head>
<body>
@(Html.Infragistics().Tree(Model)
.InitialExpandDepth(1)
.Height("500px")
.Width("100%")
.ID("arbolServicioFuncion")
.HotTracking(false)
.Bindings(b =>
{
b.TextKey("DesServicio")
.PrimaryKey("CodServicio")
.ValueKey("CodServicio")
.ChildDataProperty("FuncionesServicio")
.NodeContentTemplate("<span class='node'>${DesServicio}</span>");
b.Bindings(b2 =>
{
b2.TextKey("DesFuncion")
.PrimaryKey("CodFuncion")
.ValueKey("CodFuncion")
.NodeContentTemplate("<span class='node-pill'>${DesFuncion}</span>");
});
})
.DataBind()
.Render()
)
</body>
body {
background-color: #f5f5f5;
}
/* Remove selected state style */
.ui-state-active {
border: none !important;
background-color: unset !important;
}
/* Remove focused state style */
.ui-state-focus {
border: none !important;
background-color: unset !important;
}
/* Position icon on the right */
.ui-igtree-expander {
left: unset !important;
right: .8em;
}
/* Set chevron-down icon */
.ui-icon-triangle-1-s:before {
font-family: "Font Awesome 6 Free";
font-weight: 900;
content: "\f078";
font-size: 16px;
color: #d32f2f;
}
/* Set chevron-up icon */
.ui-icon-triangle-1-e:before {
font-family: "Font Awesome 6 Free";
font-weight: 900;
content: "\f077";
font-size: 16px;
color: #d32f2f;
}
.ui-igtree-parentnode {
padding-left: unset;
padding-right: 1.9em;
}
/* Increase child node indentation */
.ui-igtree-node-nochildren {
margin-left: 2.5em;
}
/* Style tree container */
.ui-igtree {
width: fit-content !important;
background-color: #fff;
padding: 24px;
border-radius: 24px;
box-shadow: 0px 0px 4px grey;
}
/* Style parent node */
.node {
font-weight: 500;
}
/* Style child node */
.node-pill {
background: #fde7ea;
color: #d32f2f;
padding: 4px 8px;
border-radius: 8px;
font-size: 1rem;
font-weight: 500;
}
/* Draw connection line from parent to child node */
.ui-igtree .ui-igtree-node-nochildren::before {
content: "";
position: absolute;
left: -1.8em;
top: -4px;
height: 24px;
width: 32px;
border-left: 1.5px solid #dcdcdc;
border-bottom: 1.5px solid #dcdcdc;
}
Please let me know if you need any further information on the matter.
Sincerely,
Riva Ivanova
Software Developer
Infragistics
Hello,
I have been looking into your question, and for high‑performance Angular apps (especially those using feature‑rich UI libraries like Ignite UI for Angular), the best wins usually come from reducing what you ship, rendering only what’s visible, and persisting only the minimum state you actually need.
Below are some recommendations, along with links to our documentation for further details and examples.
1) Keep CSS payload small (prevents “cache bloat” from huge stylesheets)
1.1) Exclude unused component themes at build time
Ignite UI’s theming engine can generate a stylesheet that includes all component themes, but the docs explicitly recommend optimizing this by excluding the ones you don’t use (which reduces the CSS that ends up cached by the browser).
- The @include theme() mixin supports an $exclude parameter so you can omit unused component themes.
- The library exposes a $components map to help you compute exclusions based on what you actually include.
1.2) Route-level (lazy) theming for heavy components
If a “heavy” component (e.g., TreeGrid) exists on only one route, you can lazy-load that route and move the component theme into the route/component stylesheet so it’s not part of the initial cached CSS. This approach reduces top-level CSS dramatically and only delivers the heavier grid styles when the user navigates to that feature area.
Customizing Ignite UI for Angular Theming
2) Reduce JS bundle size via multiple entry points + code splitting (smaller cached JS)
Starting with v21.0.0, Ignite UI for Angular supports multiple entry points, enabling better tree-shaking, code splitting, and lazy loading so you only ship what you use.
2.1) Import from the most specific entry point
Instead of importing everything from igniteui-angular, the docs recommend importing from specific entry points, such as:
- igniteui-angular/grids/grid
- igniteui-angular/input-group
- igniteui-angular/core (for utilities/services)
This reduces initial bundle size and improves load performance because modern bundlers can eliminate unused code more effectively.
2.2) Combine entry points with Angular lazy loading
Pairing the entry point architecture with Angular lazy loading further reduces initial bundle weight.
Code Splitting and Multiple Entry Points
Additionally, since the grids are quite complex and feature-rich components, some grid-specific recommendations can improve the performance:
3) Prevent memory growth in data-heavy views with Grid virtualization
If your application renders large tables/lists, the DOM size becomes a major memory driver. Ignite UI’s IgxGrid virtualizes content vertically and horizontally using igxForOf, rendering only what is visible in the viewport and swapping data as the user scrolls.
Best practices to ensure virtualization stays effective:
- Keep grid dimensions constrained (default is width/height 100%). Virtualization activates when content can’t fit, and scrollbars are needed.
- Avoid setting grid width or height to null unless you intentionally want all rows/columns rendered (which increases DOM and memory).
Angular Grid Virtualization and Performance
4) Avoid browser storage “bloat” when persisting grid state
Ignite UI provides igxGridState for saving/restoring grid state via getState(), and setState(), and storing the serialized state string can be done in storage such as sessionStorage/localStorage.
You can pass feature names (or a list of features) to getState() to retrieve only parts of the state (e.g., sorting/filtering) rather than everything. Also, the directive supports an options object that lets you disable tracking for specific features, ensuring they’re not included in saved state and therefore not inflating stored payloads.
Angular Grid State Persistence
Please let me know if you need any further information regarding this matter.
Sincerely,
Riva Ivanova
Software Developer
Infragistics
Hello,
Thank you for posting in our community!
After looking into both images, what I can say is that the desired look can be achieved by setting some of the IgGrid Paging properties and slightly adjusting the CSS.
The usual look of the IgGrid Paging (which is observed in the first image) is achieved by simply using this code:
.Features(f =>
{
f.Paging()
.PageSize(10);
})
To achieve the design in the second image, you will need to:
- Remove the pager records label (“1 – 10 of 10 records”)
- Remove the first and last page buttons
- Move the drop-down in the pager
- Change the drop-down label from “Show” to “Ver”
- Remove the drop-down trailing label (“records”)
- Remove the “Prev” and “Next” button labels.
- (Optional) Always show one page count. (< 1 > and not < 1 2 3 >)
- Align Next, Page Count, and Last buttons to the left and the drop-down to the right.
Points 1 to 7 can be handled via the paging properties:
.Features(f =>
{
f.Paging()
.PageSize(10)
.ShowPagerRecordsLabel(false) // handles 1
.ShowFirstLastPages(false) // handles 2
.PageSizeDropDownLocation("inpager") // handles 3
.Locale( // handles 4, 5, 6
@"{
pageSizeDropDownLabel: 'Ver',
pageSizeDropDownTrailingLabel: '',
prevPageLabelText: '',
nextPageLabelText: ''
}"
)
.VisiblePageCount(1); // handles 7
})
Point 8 can be handled via CSS:
.ui-iggrid .ui-iggrid-paging {
float: none;
}
div.ui-helper-clearfix.ui-iggrid-pagesizedropdowncontainer {
float: right;
}
All supported options can be found in the IgGrid Paging API documentation here.
Please test it on your side and let me know if you need any further information on the matter.
Sincerely,
Riva Ivanova
Software Developer
Hello,
Thank you for posting in our community!
In version 21.1.0, a new feature was introduced for the IgxTooltipTarget – trigger events. Now, the tooltip target allows you to set which event triggers will show or hide the tooltip. Expects a comma-separated string of different event triggers, and the defaults are pointerenter for the showTriggers and pointerleave and click for the hideTriggers.
Before this change, the tooltip target reacted to mouseenter and mouseleave. As well as click for hiding, this remains unchanged.
This feature can be checked in our Triggers sample here.
Additionally, there were some behavioral changes in version 20.1.0 related to the show and hide delays. They were made shorter – from 500ms to 200ms for showDelay and 300ms for hideDelay. However, this change should be noticeable in version 21.0.10, too.
While testing the reported behaviors with the Triggers sample, I did not notice the tooltip appear more aggressively/without a delay, or for it to remain open.

However, if you are experiencing the showing without delay when quickly hovering on the tooltip itself, similar to the demo below, then please note that this behavior is expected. Since version 20.1.0, the tooltip remains open while interacting with it, and in the following case – quickly interacting with the tooltip while it is still showing, the show animation is canceled, and the tooltip is shown immediately. This is expected and by design.

To conclude, when the event triggers feature was introduced, it did not affect the delay behavior in any way. However, what I can suggest is checking out the showTriggers and hideTriggers options, changing them to mouseenter/mouseleave to simulate the previous behavior. Also, if needed, you can adjust the showDelay and hideDelay options too.
Please test the sample as well as the suggestions on your side and let me know if you need any further information on the matter.
Sincerely,
Riva Ivanova
Software Developer