title: Fabric UI DetailsList control - Dynamically load group items
body: <p>I'm using grouped DetailsList Fabric UI component in custom SPFx webpart for displaying <a href="https://developer.microsoft.com/en-us/fabric/#/controls/web/detailslist/grouped" rel="nofollow noreferrer">list data</a>.</p>
  
  <p>I need to load items of the group dynamically from the server by the API call after group expand, but can't find any available group expand callbacks in DetailsList component with available exposed group props (name of the group, etc.) as a method parameter for building a request string. It should look like that:</p>
  
  <pre><code>https://contoso.sharepoint.com/site/_api/web/Lists/getbytitle('ListTitle')/RenderListDataAsStream?@listUrl=&amp;View=&amp;IsGroupRender=TRUE&amp;DrillDown=1&amp;GroupString=%3B%23Exel%20Format%20Files%3B%23%3B%23&amp;
  </code></pre>
  
  <p>Basically, I want to achieve behavior of the standard modern Document Library webpart existing in Sharepoint 2019. Just need a callback on group expand for update items array. Any other ways to achieve this with DetailsList component?</p>
  
  <p>Code sample of the component (from documentation):</p>
  
  <pre><code>import * as React from 'react';
  import {
    BaseComponent,
    DefaultButton,
    DetailsHeader,
    DetailsList,
    IColumn,
    IDetailsHeaderProps,
    IDetailsList,
    IGroup,
    IRenderFunction,
    IToggleStyles,
    mergeStyles,
    Toggle
  } from 'office-ui-fabric-react';
  
  const margin = '0 20px 20px 0';
  const controlWrapperClass = mergeStyles({
    display: 'flex',
    flexWrap: 'wrap'
  });
  const toggleStyles: Partial&lt;IToggleStyles&gt; = {
    root: { margin: margin },
    label: { marginLeft: 10 }
  };
  
  export interface IDetailsListGroupedExampleItem {
    key: string;
    name: string;
    color: string;
  }
  
  export interface IDetailsListGroupedExampleState {
    items: IDetailsListGroupedExampleItem[];
    groups: IGroup[];
    showItemIndexInView: boolean;
    isCompactMode: boolean;
  }
  const _blueGroupIndex = 2;
  
  export class DetailsListGroupedExample extends BaseComponent&lt;{}, IDetailsListGroupedExampleState&gt; {
    private _root = React.createRef&lt;IDetailsList&gt;();
    private _columns: IColumn[];
  
    constructor(props: {}) {
      super(props);
  
      this.state = {
        items: [
          { key: 'a', name: 'a', color: 'red' },
          { key: 'b', name: 'b', color: 'red' },
          { key: 'c', name: 'c', color: 'blue' },
          { key: 'd', name: 'd', color: 'blue' },
          { key: 'e', name: 'e', color: 'blue' }
        ],
        // This is based on the definition of items
        groups: [
          { key: 'groupred0', name: 'Color: "red"', startIndex: 0, count: 2 },
          { key: 'groupgreen2', name: 'Color: "green"', startIndex: 2, count: 0 },
          { key: 'groupblue2', name: 'Color: "blue"', startIndex: 2, count: 3 }
        ],
        showItemIndexInView: false,
        isCompactMode: false
      };
  
      this._columns = [
        { key: 'name', name: 'Name', fieldName: 'name', minWidth: 100, maxWidth: 200, isResizable: true },
        { key: 'color', name: 'Color', fieldName: 'color', minWidth: 100, maxWidth: 200 }
      ];
    }
  
    public componentWillUnmount() {
      if (this.state.showItemIndexInView) {
        const itemIndexInView = this._root.current!.getStartItemIndexInView();
        alert('first item index that was in view: ' + itemIndexInView);
      }
    }
  
    public render() {
      const { items, groups, isCompactMode } = this.state;
  
      return (
        &lt;div&gt;
          &lt;div className={controlWrapperClass}&gt;
            &lt;DefaultButton onClick={this._addItem} text="Add an item" styles={{ root: { margin: margin } }} /&gt;
            &lt;Toggle label="Compact mode" inlineLabel checked={isCompactMode} onChange={this._onChangeCompactMode} styles={toggleStyles} /&gt;
            &lt;Toggle
              label="Show index of first item in view when unmounting"
              inlineLabel
              checked={this.state.showItemIndexInView}
              onChange={this._onShowItemIndexInViewChanged}
              styles={toggleStyles}
            /&gt;
          &lt;/div&gt;
          &lt;DetailsList
            componentRef={this._root}
            items={items}
            groups={groups}
            columns={this._columns}
            ariaLabelForSelectAllCheckbox="Toggle selection for all items"
            ariaLabelForSelectionColumn="Toggle selection"
            onRenderDetailsHeader={this._onRenderDetailsHeader}
            groupProps={{
              showEmptyGroups: true
            }}
            onRenderItemColumn={this._onRenderColumn}
            compact={isCompactMode}
          /&gt;
        &lt;/div&gt;
      );
    }
  
    private _addItem = (): void =&gt; {
      const items = this.state.items;
      const groups = [...this.state.groups];
      groups[_blueGroupIndex].count++;
  
      this.setState(
        {
          items: items.concat([
            {
              key: 'item-' + items.length,
              name: 'New item ' + items.length,
              color: 'blue'
            }
          ]),
          groups
        },
        () =&gt; {
          if (this._root.current) {
            this._root.current.focusIndex(items.length, true);
          }
        }
      );
    };
  
    private _onRenderDetailsHeader(props: IDetailsHeaderProps, _defaultRender?: IRenderFunction&lt;IDetailsHeaderProps&gt;) {
      return &lt;DetailsHeader {...props} ariaLabelForToggleAllGroupsButton={'Expand collapse groups'} /&gt;;
    }
  
    private _onRenderColumn(item: IDetailsListGroupedExampleItem, index: number, column: IColumn) {
      const value = item &amp;&amp; column &amp;&amp; column.fieldName ? item[column.fieldName as keyof IDetailsListGroupedExampleItem] || '' : '';
  
      return &lt;div data-is-focusable={true}&gt;{value}&lt;/div&gt;;
    }
  
    private _onShowItemIndexInViewChanged = (event: React.MouseEvent&lt;HTMLInputElement&gt;, checked: boolean): void =&gt; {
      this.setState({ showItemIndexInView: checked });
    };
  
    private _onChangeCompactMode = (ev: React.MouseEvent&lt;HTMLElement&gt;, checked: boolean): void =&gt; {
      this.setState({ isCompactMode: checked });
    };
  }
  </code></pre>