From 74275f44c71e815b85bf7cea66e3bf98c57fb7e4 Mon Sep 17 00:00:00 2001 From: Aarish <99556002+aarishgilani@users.noreply.github.com> Date: Mon, 29 Jul 2024 16:49:30 -0500 Subject: [PATCH] Accessible SVG icons: Add title tag inside SVG if the title attribute is set (#245) * Add title tag to SVG's if title attribute is set * Update src/Svg.php * Pass tile directly to the method as param * Better variable name for title element * Update regular expression, consider may be passed with not attributes. * Svg class tests to ensure aria attribute and title element are added correctly. * Add role as img: WCAG best practice * Update tests to check for role attribute * Update README.md - Add Accessibility section * Update README.md * Include usage example --------- Co-authored-by: Dries Vints Co-authored-by: Nicky <36059299+jdmghost@users.noreply.github.com> --- README.md | 40 ++++++++++++++++++++++++++++++++++++++++ src/Svg.php | 28 ++++++++++++++++++++++++++++ tests/SvgTest.php | 18 ++++++++++++++++++ 3 files changed, 86 insertions(+) diff --git a/README.md b/README.md index 13f4a36..aa84684 100644 --- a/README.md +++ b/README.md @@ -541,6 +541,46 @@ If you'd like, you can use the `svg` helper to expose a fluent syntax for settin {{ svg('camera')->id('settings-icon')->dataFoo('bar')->dataBaz() }} ``` +### Accessibility + +If the icon should have semantic meaning, a text alternative can be added with the title attribute. Refer to the [Usage](https://github.com/blade-ui-kit/blade-icons#usage) section of this documentation to learn how to add an attribute. + +For almost all use cases, your icon will be assuming the role of an image. This means that deciding on if your icon has any semantic meaning, or what that semantic meaning is, you can use the [WCAG alt text decision tree](https://www.w3.org/WAI/tutorials/images/decision-tree/). + +If your icon has semantic meaning, using the title attribute will apply the following features to the SVG element: + +- Child element of `` with a unique ID containing the value that was passed +- `title` attribute containing the value that was passed +- `role="img"` +- `aria-labelledby` to refer to the unique ID of the title element + +Example usage: + +```blade + + +@svg('camera', ['title' => 'camera']) +``` + +Example result: + +```html + + + Camera + + + +``` + +If your icon does not have semantic meaning, you may want to hide the icon to reduce overall document clutter. You may do this by adding `aria-hidden="true"` to your icon. + ## Building Packages If you're interested in building your own third party package to integrate an icon set, it's pretty easy to do so. We've created [a template repo for you to get started with](https://github.com/blade-ui-kit/blade-icons-template). You can find the getting started instructions in its readme. diff --git a/src/Svg.php b/src/Svg.php index 38956c9..86b6557 100644 --- a/src/Svg.php +++ b/src/Svg.php @@ -36,8 +36,36 @@ public function contents(): string return $this->contents; } + /** + * This method adds a title element and an aria-labelledby attribute to the SVG. + * To comply with accessibility standards, SVGs should have a title element. + * Check accessibility patterns for icons: https://www.deque.com/blog/creating-accessible-svgs/ + */ + public function addTitle(string $title): string + { + // generate a random id for the title element + $titleId = 'svg-inline--title-'.Str::random(10); + + // create title element + $titleElement = ''.$title.''; + + // add aria-labelledby attribute to svg element + $this->attributes['aria-labelledby'] = $titleId; + + // add role attribute to svg element + $this->attributes['role'] = 'img'; + + // add title element to svg + return preg_replace('/]*>/', "$0$titleElement", $this->contents); + } + public function toHtml(): string { + // Check if the title attribute is set and add a title element to the SVG + if (array_key_exists('title', $this->attributes)) { + $this->contents = $this->addTitle($this->attributes['title']); + } + return str_replace( 'renderAttributes()), diff --git a/tests/SvgTest.php b/tests/SvgTest.php index 78f64b0..1951c38 100644 --- a/tests/SvgTest.php +++ b/tests/SvgTest.php @@ -199,4 +199,22 @@ public function it_can_pass_in_attributes_fluently() $this->assertSame('', $svg->toHtml()); } + + /** @test */ + public function it_can_add_title_tag_if_title_attribute_is_passed() + { + $svg = new Svg('heroicon-s-camera', '', ['title' => 'Camera']); + + $this->assertStringContainsString('>toHtml()); + $this->assertStringContainsString('role="img">', $svg->toHtml()); + } }