1 of 60

Implementing an accessibility-focused design system in Drupal

Amy M. Drayer

jen neveau

Gabe Ormsby

2 of 60

University of Minnesota campus

3 of 60

Why is this statement important?

4 of 60

“This is how bad design makes it out into the world. Not due to malicious intent, but having no intent at all.”

-Mike Monteiro

5 of 60

Design with intent

Putting principles into action

Project goals and vision

6 of 60

(Universally) Accessible

Honest

Inclusive

Mindful

Private

Simple

Sustainable

7 of 60

(Universally) Accessible

Deliver content and services where barriers to access are removed for all people to use regardless of technology, format, or methods of delivery.

Avoid building to one way of doing or being. Build to be understandable, in a way that allows us to be human and make errors.

8 of 60

Honest

Be transparent.

Provide only accurate content written with non-biased language and clearly identify opinionated content. Fight disinformation, or the act of intentionally deceiving in content and algorithms.

9 of 60

Inclusive

Lead with person-first design, designing with people, not for them. Be aware of our own biases and assumptions, and recognize we are not the user.

Embrace people as complex beings, where average doesn’t exist.

10 of 60

Mindful

Make decisions that prioritize user wellbeing, don’t build to steal attention, and avoid deceptive and manipulative patterns.

11 of 60

Private

Promote and ensure privacy through security and personal data ownership. Provide these tenets in systems and services to the best of our ability and be transparent where we cannot.

12 of 60

Simple

Simple is challenging; it’s curating and cultivating the message concisely and clearly.

It’s discovering the most elegant semantic technical solution, and the intentional use of the resources available.

13 of 60

Sustainable

Factor in energy source and consumption for optimizations, from server to client side. Just as people do not deserve a reduced experience, our planet does not deserve to suffer the consequences of bad design and web delivery.

Sustainability is as much about our planet’s wellbeing as it is our own, as they are intertwined.

14 of 60

U Libraries Design System

15 of 60

(Universally) Accessible

Honest

Inclusive

Mindful

Private

Simple

Sustainable

16 of 60

Accessibility is aesthetic.

simplify code

simplify selectors #this-one #that-thing .this-button span�:not, ~, +, :first-child, :only-child, :nth-child(), :first-of-type, :last-of-type, :nth-of-type(), [att=value]

honor user settings to improve accessibility

mind high CPU styles for sustainability

  • border-radius
  • box-shadow and text-shadow
  • opacity
  • transform
  • filter
  • position: fixed

17 of 60

Why is this statement important?

Making it work in Drupal

  • Provide a web components-based editing system for content contributors
  • Theme using web components provided by the design system

18 of 60

Why is this statement important?

The editing experience for content contributors

19 of 60

Why is this statement important?

Removing options...

  • Prevents layout and content choices that are counterproductive (break the intent of the design system)
  • Saves the content contributor from having to think about irrelevant choices

20 of 60

Why is this statement important?

Setting constraints

  • No Layout Builder
  • No In Place Editing
  • Minimal WYSIWYG toolbar configurations, tailored to specific content (Inline elements, lists, larger-scoped components)

21 of 60

Why is this statement important?

Keep the Design System in mind

  • Editing interface matches Design System language for each web component
  • Field-level help text links back to Design System for details and rationale
  • Staff training similarly references both Design System components and Drupal implementation

22 of 60

Design System-to-Drupal

The Design System gives us web components and the canonical markup for them.

23 of 60

24 of 60

Why is this statement important?

Applying the abstract web components to Drupal

25 of 60

Why is this statement important?

Paragraphs as building blocks

  • https://drupal.org/project/paragraphs
  • Design system components were implemented as Paragraphs
  • Allows for nesting of elements (cards in card decks, text paragraphs inside sections)
  • Each type contains fields for content and also for editor-accessible settings.

26 of 60

Example paragraph types

27 of 60

Page body as Paragraphs

28 of 60

Content section

fields

29 of 60

The editing experience in summary

  • The "blob of body text" and wealth of rich text options is gone.
  • Content editors think structurally about how their content fits into available components.
  • Formatting options are tightly constrained to those that make sense within a given component and which meet accessibility requirements.
  • Fields are mostly for displayed content, but some turn into configuration as the theme processes them.

30 of 60

Theming (the Paragraphs) to fit the design system

31 of 60

Theme flow as a 3-step process

  • Catch: Hook into the theming process where Drupal would normally go -- The Twig files
    • For Paragraphs, paragraph--paragraph-type.html.twig
  • Tweak: Manipulate inbound data where needed to work with design system expectations -- Twig or theme hooks
  • Redirect: Send tweaked data to theme's design system components

32 of 60

Theme flow

Step 1: Catch�

33 of 60

[...]�<!-- THEME DEBUG -->�<!-- THEME HOOK: 'paragraph' -->�<!-- FILE NAME SUGGESTIONS:� * paragraph--ds-content-section--default.html.twig� x paragraph--ds-content-section.html.twig� * paragraph--default.html.twig� * paragraph.html.twig�-->�<!-- BEGIN OUTPUT from 'sites/www.lib.umn.edu/themes/umnlib/templates/paragraphs/paragraph--ds-content-section.html.twig' -->

<section class="color-block hero" id="homepage">�[...]

Catch: Standard Drupal template behavior

34 of 60

"Catch" just means create a template where Drupal is going to look. For a specific example:

Our design system component: Content section

Implemented as: A paragraph of type ds-content-section

Catch the theming process at: our-theme/templates/paragraphs/� paragraph--ds-content-section.html.twig

Let's dig into that Twig file for the next two steps...

35 of 60

Excerpt 1: paragraph--ds-content-section.html.twig

{#�/**� * This template passes final rendering off to a design system pattern template� * in theme's templates/components/ directory. Here, we munge the data just� * enough to fit the expectations of the abstract DS pattern. That means:� [...]� * This approach will allow other Drupal Paragraphs, Block or Views, to also� * rely on the component templates, by ensuring a consistent 'inbound'� * vocabulary.� */�#}

36 of 60

Excerpt 2: paragraph--ds-content-section.html.twig

{% set section_classes = content.field_ds_section_classes|render|striptags|trim|split(' ') %}

{% set section_id = content.field_ds_section_id|render|striptags|trim|split(' ')|first ?: 's-' ~ paragraph.id() %}

This is Step 2...Tweak!

37 of 60

Why tweak? Paragraph data is not necessarily Component data

  • Stuff that makes sense for an editor to enter may not perfectly map to stuff a design system component needs
  • We alter existing data and add new data when sending a Paragraph to a Component
  • Easy stuff can happen in Twig
  • Complicated stuff happens in umnlib.theme, mostly preprocess and alter hooks -- 2,000 lines worth (maybe 50% comments)
  • Recall the Paragraph entry form for a content section...

38 of 60

Part of the form for a content section paragraph

39 of 60

Excerpt 2 (again): paragraph--ds-content-section.html.twig

{% set section_classes = content.field_ds_section_classes|render|striptags|trim|split(' ') %}

{% set section_id = content.field_ds_section_id|render|striptags|trim|split(' ')|first ?: 's-' ~ paragraph.id() %}

40 of 60

Excerpt 3: paragraph--ds-content-section.html.twig

{% embed '@components/section/section.html.twig' with {� content: content.field_section_items,� heading: content.field_ds_section_heading,� heading_element: content.heading_element,� subtitle: content.field_section_subtitle,� section_classes: section_classes,� section_id: section_id,� classes: classes,� back_to_top: content.back_to_top,�} %}�{% endembed %}

...And here is Step 3: Redirect. What's going on here?

41 of 60

The "redirect" step relies on the Components module

  • https://drupal.org/project/components
  • "The Components module makes it easier for a theme to organize its components. It allows themes (and modules) to register Twig namespaces and provides some additional Twig functions and filters for use in Drupal templates."
  • Rephrased, allows us to define a special templates directory for components in our theme.info.yml file and use `@components` in Twig to reference that directory.

42 of 60

Excerpt of umnlib.info.yml

...

components:� namespaces:� components: templates/components�...

43 of 60

What's in�templates/�components?

44 of 60

Excerpt 3 (again): paragraph--ds-content-section.html.twig

{% embed '@components/section/section.html.twig' with {� content: content.field_section_items,� heading: content.field_ds_section_heading,� heading_element: content.heading_element,� subtitle: content.field_section_subtitle,� section_classes: section_classes,� section_id: section_id,� classes: classes,� back_to_top: content.back_to_top,�} %}�{% endembed %}

45 of 60

That was the theme template for the content section paragraph type.

Let's go look at the theme template for the content section web component.

46 of 60

Excerpt 1: templates/components/section/section.html.twig

[...]�/**� * Available variables:� * - content: The content items within the article. Optional.� * - heading: The heading for the article. Required.� * - heading_element: The appropriate level heading. Required.� * - subtitle: Extension to heading, not included in side navigation. Optional.� * - back_to_top: Boolean flag indication whether to include a 'back to top' \� link. Optional.� * - section_classes: Array. Class options from paragraph type. Optional.� * - section_id: String. ID attribute value. Optional.� * - classes: Classes array passed by parent theme or module.�[...]

47 of 60

Excerpt 2: templates/components/section/section.html.twig

[...]�* This file may be used via twig 'embed' by any number of theme templates for�* Views, Blocks, or Paragraphs. The calling template is responsible for�* altering source data to fit the pattern's expected variables.�*�* See this theme's templates/paragraphs/paragraph--ds-content-section.html.twig�* for a sample implementation.�*/�[...]

48 of 60

Excerpt 3: templates/components/section/section.html.twig

<section{{ attributes.addClass(section_classes).setAttribute('id', section_id) }}>�{% if subtitle.0 %}� <{{heading_element}}>� {{ heading }} <span class="subtitle">{{ subtitle }}</span>� </{{heading_element}}>�{% else %}� <{{heading_element}}>{{ heading }}</{{heading_element}}>�{% endif %}�{% if content|render %}� {{ content }}�{% endif %}�{% if back_to_top %}� <p><a href="#top">Back to top</a></p>�{% endif %}�</section>

49 of 60

Recap: Implementing our Design System in a Drupal theme

  1. Use the default paragraph--paragraph-type.html.twig files to catch the theme flow
  2. Tweak data available to the paragraph type right in the twig template or through theme alter or preprocess functions to fit design system component needs
  3. Redirect rendering to a web component template with the help of the Component Libraries module and Twig embed functionality
  4. The same approach works with Views, Blocks, and other templates

50 of 60

Tweaking revisited: Fixing a thing that's bugged me since 2008

Remember this from our component template section.html.twig?

<{{heading_element}}>{{ heading }}</{{heading_element}}>

51 of 60

umnlib_get_heading_level():

A helper function in our theme that finds the appropriate heading level for any heading-like field.

  • We know what fields are used for headings and we know what paragraph types they are in (card decks and content sections)
  • Instead of hard coding "<h2>" or "<h3>" in a twig template and hoping it works, we use "$heading_element"
  • Probably rather expensive, but we have Varnish caching in front.

52 of 60

Why is this statement important?

Accessible content

53 of 60

Content strategy

“The University of Minnesota Libraries’ website prioritizes the support of users new to our site and services, and by doing so, supports all users in their goal to find and access our resources and apply them to their work, and our goal to engage and inspire our diverse community of users.”

54 of 60

Why is this statement important?

Content guidelines

55 of 60

Why is this statement important?

Content guidelines

  • Use descriptive headings and links
  • Use sentence casing
  • Write for a 8th grade or lower literacy level
  • Use short sentences and paragraphs
  • Use bulleted lists

56 of 60

Why is this statement important?

Content audit and remediation

57 of 60

Why is this statement important?

Content governance and workflow

Draft > Pending WCMC review > Published

Pending deletion or Archived

58 of 60

Lessons learned

  • Content first development worked! (mostly)
  • The shift away from WYSIWYG authoring was hard.
  • Ongoing communication is key.
  • Workflow is important, but keep it simple.
  • Real content doesn’t always fit.

59 of 60

Lessons learned

  • It paid off!

60 of 60

Thank you.

Amy Drayer adrayer@umn.edu�jen neveau jneveau@umn.edu �Gabe Ormsby gormsby@umn.edu