{"id":17175169,"url":"https://github.com/sophiamersmann/friendly-charts","last_synced_at":"2025-03-24T21:17:36.212Z","repository":{"id":59003244,"uuid":"516480631","full_name":"sophiamersmann/friendly-charts","owner":"sophiamersmann","description":"Screen reader friendly charts with minimal effort","archived":false,"fork":false,"pushed_at":"2023-02-09T08:48:35.000Z","size":745,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-05T23:23:26.579Z","etag":null,"topics":["a11y","charts","keyboard-accesible","screen-reader"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sophiamersmann.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-07-21T18:26:22.000Z","updated_at":"2022-09-04T15:46:59.000Z","dependencies_parsed_at":"2024-12-02T19:15:45.003Z","dependency_job_id":null,"html_url":"https://github.com/sophiamersmann/friendly-charts","commit_stats":{"total_commits":66,"total_committers":1,"mean_commits":66.0,"dds":0.0,"last_synced_commit":"0676c83ddbc1f813326ebc69c66090b3862d002b"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sophiamersmann%2Ffriendly-charts","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sophiamersmann%2Ffriendly-charts/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sophiamersmann%2Ffriendly-charts/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sophiamersmann%2Ffriendly-charts/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sophiamersmann","download_url":"https://codeload.github.com/sophiamersmann/friendly-charts/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245352092,"owners_count":20601093,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["a11y","charts","keyboard-accesible","screen-reader"],"created_at":"2024-10-14T23:55:54.446Z","updated_at":"2025-03-24T21:17:36.173Z","avatar_url":"https://github.com/sophiamersmann.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Friendly Charts\n\nScreen reader friendly charts with minimal effort\n\n## Install\n\n```bash\nnpm install friendly-charts\n```\n\n\u003e **Warning**\n\u003e\n\u003e Under construction\n\n## Features\n\nYou ✨ bring your own chart ✨ and Friendly Charts will:\n\n- expose a chart description to screen readers\n- make your chart keyboard accessible, allowing screen reader users to explore charts via keyboard interactions\n\nFriendly Charts exports a number of functions that expect a DOM element as input. Friendly Charts is framework agnostic but in Svelte and Solid, for example, the exported functions can be applied as use directives/actions.\n\nThe interaction design for keyboard accessible charts is borrowed from [Visa Chart Components](https://developer.visa.com/pages/chart-components):\n\n- _TAB_ to the chart area\n- _ENTER_ to drill down a level\n- _ESCAPE_ to drill up a level\n- _LEFT_ and _RIGHT_ arrows to move between sibling elements\n- _UP_ and _DOWN_ arrows to move across groups\n\nhttps://user-images.githubusercontent.com/12461810/191855514-5c5db343-8b8c-48e2-8829-bf7314938def.mov\n\n## Example\n\nTo make a chart friendly, apply the `chart` function to a container element, providing a chart title, subtitle and description. To make the chart keyboard accessible, use the `axis`, `symbol` and `group` functions to outline the chart's structure and provide accessible names. Friendly charts will then wire up the necessary focus and event management to let a screen reader user navigate the chart via keyboard interactions. For example, in Svelte:\n\n```svelte\n\u003c!-- BarChart.svelte --\u003e\n\n\u003cscript\u003e\n  import { chart } from 'friendly-charts';\n  import locale from 'friendly-charts/locale/en-US';\n\n  const data = [\n    { category: \"A\", value: 82 },\n    { category: \"B\", value: 50 },\n    { category: \"C\", value: 10 }\n  ];\n\u003c/script\u003e\n\n\u003c!-- FRIENDLY ACTION: declare a bar chart and link to its title and subtitle --\u003e\n\u003cdiv use:chart={{ title: '.title', subtitle: '.subtitle', type: 'bar', locale }} \u003e\n  \u003chgroup\u003e\n    \u003ch2 class=\"title\"\u003e Chart title \u003c/h2\u003e\n    \u003cp class=\"subtitle\"\u003e Chart subtitle \u003c/p\u003e\n  \u003c/hgroup\u003e\n\n  \u003csvg\u003e\n    \u003cAxisX /\u003e\n    \u003cBars {data} /\u003e\n  \u003c/svg\u003e\n\u003c/div\u003e\n```\n\n```svelte\n\u003c!-- AxisX.svelte --\u003e\n\n\u003cscript\u003e\n  import { axis } from 'friendly-charts';\n\u003c/script\u003e\n\n\u003c!-- FRIENDLY ACTION: declare the x-axis, give it a label and link to its ticks --\u003e\n\u003cg use:axis={{ label: 'Axis label', direction: 'x', ticks: '.tick text' }}\u003e\n  {#each [0, 20, 40, 60, 80] as tick (tick)}\n    \u003cg class=\"tick\" transform=\"translate({getX(tick)},{boundedHeight})\"\u003e\n      \u003cline y1={-boundedHeight} stroke=\"lightgray\" /\u003e\n      \u003ctext fill=\"gray\"\u003e {tick} \u003c/text\u003e\n    \u003c/g\u003e\n  {/each}\n\u003c/g\u003e\n```\n\n```svelte\n\u003c!-- Bars.svelte --\u003e\n\n\u003cscript\u003e\n  import { symbol } from 'friendly-charts';\n\n  export let data;\n\u003c/script\u003e\n\n\u003cg\u003e\n  {#each data as d, i (d.category)}\n    \u003cg class=\"bar\" transform=\"translate(0,{getY(i)})\"\u003e\n\n      \u003c!-- FRIENDLY ACTION: declare a bar and give it an accessible label --\u003e\n      \u003crect use:symbol={{ label: `${d.category}. ${d.value}`, type: 'bar' }} width={getX(d.value)} height={barHeight} fill=\"#0284c7\" /\u003e\n\n      \u003ctext y=\"0.75em\"\u003e {d.category} \u003c/text\u003e\n    \u003c/g\u003e\n  {/each}\n\u003c/g\u003e\n```\n\nCodeSandbox: https://codesandbox.io/s/friendly-tiny-bar-chart-10weeu?file=/App.svelte\n\n## Documentation\n\nExported are:\n\n- `chart`: exposes a chart description and makes the chart keyboard accessible\n- `axis`: declares an axis\n- `symbol`: declares a symbol (e.g. a single bar)\n- `group`: declares a group of symbols (e.g. bars of the same category)\n- `focus`: custom focus ring to highlight active elements on navigation (only needed to override default styles)\n\n### `chart(node, options)`\n\n_Exposes a chart description and makes the chart keyboard accessible_\n\n**Examples:**\n\n```js\nimport { chart } from 'friendly-charts';\nimport locale from 'friendly-charts/locale/en-US.json';\n\n// minimal configuration\nchart(node, {\n\ttitle: 'Chart title',\n\ttype: 'bar',\n\tlocale,\n});\n\n// .title and .subtitle are selectors that point to elements within the chart container\nchart(node, { title: '.title', subtitle: '.subtitle', type: 'bar', locale });\n\n// debug mode\nchart(node, {\n\ttitle: 'Chart title',\n\tsubtitle: 'Chart subtitle',\n\ttype: 'bar',\n\tlocale,\n\tdebug: true,\n});\n```\n\n**Options:**\n\n- `title` **(required)**: chart title, either the title itself or a selector that points to an element within the chart container\n- `type` (**required**; `'line'`, `'bar'`, `'scatter'`, `'slope'` or `'area'`): chart type\n- `locale` **(required)**: locale, usually imported from Friendly Charts, but you can bring your own\n- `subtitle`: chart subtitle, either the subtitle itself or a selector that points to an element within the chart container\n- `summary`: brief summary of the chart, either the summary itself or a selector that points to an element within the chart container\n- `purpose`: an explanation of the chart's purpose, either the explanation itself or a selector that points to an element within the chart container\n- `description`: long description of the chart, either the description itself or a selector that points to an element within the chart container\n- `axes`: list of axis descriptions (see Section [axis](#axisnode-options)), only needed if an axis is not visually present in the chart\n- `debug` (default: `false`): display an overlay that shows what a screen reader would announce on interaction with the chart\n\n### `axis(node, options)`\n\n_Declares an axis_\n\n**Examples:**\n\n```js\nimport { axis } from 'friendly-charts';\n\n// minimal configuration\naxis(node, { label: 'Axis label' });\n\n// .label is a selector that points to a descendant of `node`\naxis(node, { label: '.label' });\n\n// specify a direction\naxis(node, { label: 'Axis label', direction: 'x' });\n\n// infer ticks from the DOM by specifying a selector (by default, this is a continuous axis)\naxis(node, { label: 'Axis label', direction: 'y', ticks: '.tick text' });\n\n// set the axis to be categorical\naxis(node, {\n\tlabel: 'Axis label',\n\tdirection: 'x',\n\ttype: 'categorical',\n\tticks: '.tick text',\n});\n\n// specify ticks manually\naxis(node, { label: 'Axis label', direction: 'y', ticks: [0, 2, 4, 6] });\naxis(node, {\n\tlabel: 'Axis label',\n\tdirection: 'x',\n\ttype: 'categorical',\n\tticks: ['Spain', 'Italy', 'France'],\n});\n```\n\n**Options:**\n\n- `label` **(required)**: axis label, either the label itself or a selector that points to a descendant of `node`\n- `direction` (`'x'` or `'y'`): axis direction\n- `type` (`'continuous'` or `'categorical'`; default: `'continuous'`): axis type\n- `ticks`: either a list of ticks or a selector that points to the tick labels (must be descendants of `node`)\n\n### `symbol(node, options)`\n\n_Declares a symbol (e.g. a single bar)_\n\n**Examples:**\n\n```js\nimport { symbol } from 'friendly-charts';\n\n// line\nsymbol(node, { label: 'Symbol label', type: 'line' });\n\n// bar\nsymbol(node, { label: 'Symbol label', type: 'bar' });\n\n// symbol contained within a group with id `some-unique-group-id`\n// (only necessary if the symbol is not nested within that group)\nsymbol(node, {\n\tlabel: 'Symbol label',\n\ttype: 'point',\n\tparentId: 'some-unique-group-id',\n});\n```\n\n**Options:**\n\n- `label` **(required)**: symbol label, either the label itself or a selector that points to the label element\n- `type` (**required**; `'line'`, `'bar'`, `'point'` or `'area'`): symbol type\n- `id`: symbol id (automatically generated if not given)\n- `parentId`: id of the group that contains the symbol, only needed if the symbol is not a descendant of the group element\n\n### `group(node, options)`\n\n_Declares a group of symbols (e.g. bars of the same category)_\n\n**Examples:**\n\n```js\nimport { group } from 'friendly-charts';\n\n// minimal configuration\ngroup(node, { label: 'Group label' });\n\n// a group that also represents a symbol of type line (e.g. a line that contains the points it is made of)\ngroup(node, {\n\tlabel: 'Group label',\n\tid: 'unique-group-id',\n\ttype: 'line',\n});\n```\n\n**Options:**\n\n- `label` **(required)**: group label, either the label itself or a selector that points to a descendant of `node`\n- `id`: group id (automatically generated if not given)\n- `type` (`'line'`, `'bar'` or `'point'`): some groups also represent a symbol of some type (e.g. a line that contains the points it is made of)\n\n### `focus(node)`\n\n_Focus ring to highlight active elements on navigation (only needed to override default styles)_\n\n**Examples:**\n\n```js\nimport { focus } from 'friendly-charts';\n\n// the given element will be used as focus ring\nfocus(node);\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsophiamersmann%2Ffriendly-charts","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsophiamersmann%2Ffriendly-charts","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsophiamersmann%2Ffriendly-charts/lists"}