<div id="root"></div>
body {
  position: relative;
}

html,
body {
  height: 100%;
}

#root {
  display: block;
  width: 100%;
  height: 100%;
  overflow: auto;
  min-height: 80px;
  box-sizing: border-box;
  padding: 30px;
}

@keyframes k-loading-animation {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(360deg);
  }
}

.k-i-loading.k-example-loading {
  font-size: 64px;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  color: rgb(144, 152, 165);
}

.k-i-loading.k-example-loading::before,
.k-i-loading.k-example-loading::after {
  position: absolute;
  top: 50%;
  left: 50%;
  display: inline-block;
  content: "";
  box-sizing: inherit;
  border-radius: 50%;
  border-width: 0.05em;
  border-style: solid;
  border-color: currentColor;
  border-top-color: transparent;
  border-bottom-color: transparent;
  background-color: transparent;
}
.k-icon.k-i-loading.k-example-loading::before,
.k-icon.k-i-loading::after {
  content: "";
}

.k-i-loading.k-example-loading::before {
  margin-top: -0.5em;
  margin-left: -0.5em;
  width: 1em;
  height: 1em;
  animation: k-loading-animation 0.7s linear infinite;
}

.k-i-loading.k-example-loading::after {
  margin-top: -0.25em;
  margin-left: -0.25em;
  width: 0.5em;
  height: 0.5em;
  animation: k-loading-animation reverse 1.4s linear infinite;
}

.example-wrapper {
  min-height: 280px;
  align-content: flex-start;
}
.example-wrapper p,
.example-col p {
  margin: 20px 0 10px;
}
.example-wrapper p:first-child,
.example-col p:first-child {
  margin-top: 0;
}
.example-col {
  display: inline-block;
  vertical-align: top;
  padding-right: 20px;
  padding-bottom: 20px;
}
.example-config {
  margin: 0 0 20px;
  padding: 20px;
  background-color: rgba(0, 0, 0, 0.03);
  border: 1px solid rgba(0, 0, 0, 0.08);
}
.event-log {
  margin: 0;
  padding: 0;
  max-height: 100px;
  overflow-y: auto;
  list-style-type: none;
  border: 1px solid rgba(0, 0, 0, 0.08);
  background-color: white;
}
.event-log li {
  margin: 0;
  padding: 0.3em;
  line-height: 1.2em;
  border-bottom: 1px solid rgba(0, 0, 0, 0.08);
}
.event-log li:last-child {
  margin-bottom: -1px;
}
View Compiled
import * as React from "https://cdn.skypack.dev/react";
import * as ReactDOM from "https://cdn.skypack.dev/react-dom";

import {
  Grid,
  GridColumn,
  GridToolbar
} from "https://cdn.skypack.dev/@progress/kendo-react-grid";
import { DropDownList } from "https://cdn.skypack.dev/@progress/kendo-react-dropdowns";
import {
  IntlProvider,
  load,
  LocalizationProvider,
  loadMessages,
  IntlService
} from "https://cdn.skypack.dev/@progress/kendo-react-intl";

load(
  likelySubtags,
  currencyData,
  weekData,
  numbers,
  currencies,
  caGregorian,
  dateFields,
  timeZoneNames
);

loadMessages(esMessages, "es-ES");

import { process } from "https://cdn.skypack.dev/@progress/kendo-data-query";

const DATE_FORMAT = "yyyy-mm-dd hh:mm:ss.SSS";
const intl = new IntlService("en");
orders.forEach((o) => {
  o.orderDate = intl.parseDate(
    o.orderDate ? o.orderDate : "20/20/2020",
    DATE_FORMAT
  );
  o.shippedDate = o.shippedDate
    ? undefined
    : intl.parseDate(
        o.shippedDate ? o.orderDate.toString() : "20/20/2020",
        DATE_FORMAT
      );
});

const DetailComponent = (props) => {
  const dataItem = props.dataItem;
  return (
    <div>
      <section
        style={{
          width: "200px",
          float: "left"
        }}
      >
        <p>
          <strong>Street:</strong> {dataItem.shipAddress.street}
        </p>
        <p>
          <strong>City:</strong> {dataItem.shipAddress.city}
        </p>
        <p>
          <strong>Country:</strong> {dataItem.shipAddress.country}
        </p>
        <p>
          <strong>Postal Code:</strong> {dataItem.shipAddress.postalCode}
        </p>
      </section>
      <Grid
        style={{
          width: "500px"
        }}
        data={dataItem.details}
      />
    </div>
  );
};

const App = () => {
  const locales = [
    {
      language: "en-US",
      locale: "en"
    },
    {
      language: "es-ES",
      locale: "es"
    }
  ];
  const [dataState, setDataState] = React.useState({
    skip: 0,
    take: 20,
    sort: [
      {
        field: "orderDate",
        dir: "desc"
      }
    ],
    group: [
      {
        field: "customerID"
      }
    ]
  });
  const [currentLocale, setCurrentLocale] = React.useState(locales[0]);
  const [dataResult, setDataResult] = React.useState(
    process(orders, dataState)
  );

  const dataStateChange = (event) => {
    setDataResult(process(orders, event.dataState));
    setDataState(event.dataState);
  };

  const expandChange = (event) => {
    const isExpanded =
      event.dataItem.expanded === undefined
        ? event.dataItem.aggregates
        : event.dataItem.expanded;
    event.dataItem.expanded = !isExpanded;
    setDataResult({ ...dataResult });
  };

  let _pdfExport;

  const exportExcel = () => {
    _export.save();
  };

  let _export;

  const exportPDF = () => {
    _pdfExport.save();
  };

  return (
    <LocalizationProvider language={currentLocale.language}>
      <IntlProvider locale={currentLocale.locale}>
        <div>
          <Grid
            style={{
              height: "700px"
            }}
            sortable={true}
            filterable={true}
            groupable={true}
            reorderable={true}
            pageable={{
              buttonCount: 4,
              pageSizes: true
            }}
            data={dataResult}
            {...dataState}
            onDataStateChange={dataStateChange}
            detail={DetailComponent}
            expandField="expanded"
            onExpandChange={expandChange}
          >
            <GridToolbar>
              Locale:&nbsp;&nbsp;&nbsp;
              <DropDownList
                value={currentLocale}
                textField="language"
                onChange={(e) => {
                  setCurrentLocale(e.target.value);
                }}
                data={locales}
              />
              &nbsp;&nbsp;&nbsp;
            </GridToolbar>
            <GridColumn field="customerID" width="200px" />
            <GridColumn
              field="orderDate"
              filter="date"
              format="{0:D}"
              width="300px"
            />
            <GridColumn field="shipName" width="280px" />
            <GridColumn field="freight" filter="numeric" width="200px" />
            <GridColumn
              field="shippedDate"
              filter="date"
              format="{0:D}"
              width="300px"
            />
            <GridColumn field="employeeID" filter="numeric" width="200px" />
            <GridColumn
              locked={true}
              field="orderID"
              filterable={false}
              title="ID"
              width="90px"
            />
          </Grid>
        </div>
      </IntlProvider>
    </LocalizationProvider>
  );
};

ReactDOM.render(<App />, document.querySelector("#root"));
View Compiled

External CSS

  1. https://kendo.cdn.telerik.com/themes/4.41.2/default/default-main.css
  2. https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css

External JavaScript

  1. https://assets.codepen.io/3/es.js
  2. https://assets.codepen.io/3/orders.js
  3. https://assets.codepen.io/3/weekData.js
  4. https://assets.codepen.io/3/timeZoneNames.js
  5. https://assets.codepen.io/3/numbers.js
  6. https://assets.codepen.io/3/likelySubtags.js
  7. https://assets.codepen.io/3/dateFields.js
  8. https://assets.codepen.io/3/currencyData.js
  9. https://assets.codepen.io/3/currencies.js
  10. https://assets.codepen.io/3/ca-gregorian.js