Search code examples
c#.netkendo-uiscreen-readerswcag

Allowing screen reader to read Kendo UI Chart data


The website I'm developing needs to comply with the WCAG 2.0 guidelines, meaning a person should be able to access all information on the site using a screen reader. Since it's a BI dashboard making heavy use of Kendo Charts it failed the test.

I need a way for screen readers to be able to read the Kendo Charts on my website, while reusing the chart's datasource.


Solution

  • I solved this by automatically generating a table for each chart on the page.

    Create partial view which generates HTML table

    @{
        var divId = Guid.NewGuid().ToString();
        var tableId = Guid.NewGuid().ToString();
        var templateId = Guid.NewGuid().ToString();
    }
    /* Chart ID */
    @model string
    
    <div id="@divId" class="hiddenTable"></div>
    
    <script>
        (function () {
            var template = kendo.template($("#@templateId").html());
            var chartData = $("#@Model").data("kendoChart").dataSource;
            $("#@divId").prepend(template(chartData.data()));
        })();
    </script>
    
    <script id="@templateId" type="text/x-kendo-tmpl">
        # var columnNames = Chart.getColumnNamesFromData(data) #
        <table id="@tableId">
            <thead>
                <tr>
                    # for(var columnIndex = 0; columnIndex < columnNames.length; columnIndex++) { #
                        <th scope="col">#= S(columnNames[columnIndex]).humanize().s #</th>
                    # } #
                </tr>
            </thead>
            <tbody>
                # for(var i = 0, len = data.length; i < len; i++) { #
                    # if (data[i][columnNames[0]] != undefined) { #
                        <tr>
                            # for(var columnIndex = 0; columnIndex < columnNames.length; columnIndex++) { #
                                # if(columnNames[columnIndex] == 'Date') { #
                                    <th scope="row">#= kendo.toString(data[i][columnNames[columnIndex]], "MMMM yyyy") #</th>
                                #} else { #
                                    <td>#= kendo.toString(data[i][columnNames[columnIndex]] != undefined ? data[i][columnNames[columnIndex]] : 0, "n1") #</td>
                                # } #
                            # } #
                        </tr>
                    # } #
                # } #
            </tbody>
      </table>
    </script>
    

    Add CSS to hide table from view

    .hiddenTable {
        position: absolute;
        left: -10000px;
        top: auto;
        width: 1px;
        height: 1px;
        overflow: hidden;
    }
    

    Add img role to chart

    @(Html.Kendo().Chart<MyModel>()
        .Name(Guid.NewGuid().ToString())
        .HtmlAttributes(new { role = "img" })
        .DataSource(ds => ds
            .Read("GetData", "Home")
        )
    )
    

    Result

    Result HTML