Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch screen-reader-text to use VisuallyHidden #18167

Closed
14 tasks
mkaz opened this issue Oct 29, 2019 · 8 comments · Fixed by #20607
Closed
14 tasks

Switch screen-reader-text to use VisuallyHidden #18167

mkaz opened this issue Oct 29, 2019 · 8 comments · Fixed by #20607
Assignees
Labels
[Feature] UI Components Impacts or related to the UI component system Good First Issue An issue that's suitable for someone looking to contribute for the first time Needs Dev Ready for, and needs developer efforts

Comments

@mkaz
Copy link
Member

mkaz commented Oct 29, 2019

Describe the Issue

This issue is to gather all the spots for changing spots using the screen-reader-text classname to using the VisuallyHidden component. Per comment in #18127

A good reference implementation is PR #18165 that converts within the components package the spots that use screen-reader-text to VisuallyHidden component.

Why the switch?

See #18022 which introduced the VisuallyHidden component. The usage of screen-reader-text assumes a WordPress context with the proper CSS already defined. This may not always be the case, especially when pieces of the Gutenberg project are used elsewhere.

File list with screen-reader-text

  • packages/block-library/src/categories/edit.js
  • packages/block-library/src/archives/index.php
  • packages/block-library/src/gallery/edit.js
  • packages/components/src/button/style.scss
  • packages/editor/src/components/post-visibility/index.js
  • packages/editor/src/components/post-title/index.js
  • packages/editor/src/components/post-text-editor/index.js
  • packages/editor/src/components/post-preview-button/index.js
  • packages/block-editor/src/components/button-block-appender/index.js
  • packages/e2e-tests/specs/editor/various/taxonomies.test.js
  • packages/block-editor/src/components/inserter/menu.js
  • packages/block-editor/src/components/block-navigation/list.js
  • packages/edit-post/src/components/admin-notices/test/index.js
  • packages/editor/src/components/post-preview-button/test/snapshots/index.js.snap

@youknowriad - just wanted to confirm that you do what this updated across all of the above?

@youknowriad
Copy link
Contributor

youknowriad commented Oct 29, 2019

@mkaz yes :)

@mkaz mkaz added the Good First Issue An issue that's suitable for someone looking to contribute for the first time label Oct 29, 2019
@mkaz
Copy link
Member Author

mkaz commented Oct 29, 2019

I've added this as a Good First Issue and switched the list to checkboxes. If you would like to contribute feel free to take any items above as separate PRs, everything doesn't have to be done in a single PR if that makes it easier to develop and test.

@gziolo gziolo added Needs Dev Ready for, and needs developer efforts [Feature] UI Components Impacts or related to the UI component system labels Oct 30, 2019
@MarkMarzeotti
Copy link
Contributor

I am working on this issue at Contributor Day. I am focused on the three files in block-library.

packages/block-library/src/categories/edit.js
packages/block-library/src/archives/index.php
packages/block-library/src/gallery/edit.js

@adamziel
Copy link
Contributor

adamziel commented Mar 2, 2020

@mkaz I was looking into this one, and encountered more than one situation like this:

return (
    <div className={classnames( {
        'screen-reader-text': ! isSelected && RichText.isEmpty( caption ),
    } )}>
        { caption }
    </div>
);

In which case we need some additional boilerplate code:

const shouldHideCaption = ! isSelected && RichText.isEmpty( caption );
const CaptionComponent = shouldHideCaption ? VisuallyHidden : RichText;
const captionProps = shouldHideCaption ? { as: RichText } : {};
return (
    <CaptionComponent { ...captionProps }>{ caption }</CaptionComponent>
);

I feel like a better solution would be supporting an additional prop that we could use like this:

<VisuallyHidden
     as={ RichText }
     hidden={ ! isSelected && RichText.isEmpty( caption ) }
>
    { caption }
</VisuallyHidden>

What do you think?

@mkaz
Copy link
Member Author

mkaz commented Mar 3, 2020

I think the logic would be better outside the wrapper.

{ ! isSelected && RichText.isEmpty( caption ) 
   ? <VisuallyHidden>{ caption } </VisuallyHidden>
  : <div>{ caption }</div>
}

Also, I don't quite follow that logic, if the caption is empty, then what is being shown in the tag?

@adamziel
Copy link
Contributor

adamziel commented Mar 3, 2020

@mkaz I think I oversimplified my example. Let's take a look at the actual excerpt from gallery.js here:

const captionClassNames = classnames( 'blocks-gallery-caption', {
	'screen-reader-text': ! isSelected && RichText.isEmpty( caption ),
});
return (
	// ...other stuff
	<RichText
		tagName="figcaption"
		className={ captionClassNames }
		placeholder={ __( 'Write gallery caption…' ) }
		value={ caption }
		unstableOnFocus={ onFocusGalleryCaption }
		onChange={ ( value ) => setAttributes( { caption: value } ) }
		inlineToolbar
		/>
)

So we're not talking about just an empty <div />, but a component which does something even when the caption is empty. In particular, it provides a visually hidden label for screen readers. In this case, using a ternary would still require assigning props to a variable before returning:

const richTextProps = {
	tagName: "figcaption",
	className: 'blocks-gallery-caption',
	placeholder:  __( 'Write gallery caption…' ),
	value: caption,
	unstableOnFocus: onFocusGalleryCaption,
	onChange: ( value ) => setAttributes( { caption: value } ),
	inlineToolbar: true
};

return (
	// ... other stuff ...
	! isSelected && RichText.isEmpty( caption )
		? <VisuallyHidden as={ RichText } { ...richTextProps } />
		: <RichText { ...richTextProps } />
)

In which case we'd need to address one more issue: blocks-gallery-caption className would override the one provided by VisuallyHidden. A small update would be required to make sure VisuallyHidden glues blocks-gallery-caption on top of any className it receives.

One more idea that wouldn't involve any changes to VisuallyHidden would be:

const richTextElem = (
	<RichText
		tagName="figcaption"
		className={ captionClassNames }
		placeholder={ __( 'Write gallery caption…' ) }
		value={ caption }
		unstableOnFocus={ onFocusGalleryCaption }
		onChange={ ( value ) => setAttributes( { caption: value } ) }
		inlineToolbar
		/>
);

return (
	// ...other stuff
	! isSelected && RichText.isEmpty( caption ) 
		? <VisuallyHidden> { richTextElem } </VisuallyHidden>
		: { richTextElem }
)

@adamziel adamziel mentioned this issue Mar 3, 2020
5 tasks
@adamziel
Copy link
Contributor

adamziel commented Mar 3, 2020

@mkaz let's continue the conversation in the draft PR here: #20607

@mkaz
Copy link
Member Author

mkaz commented Mar 3, 2020

I think the final option will work, I'll take a look at the PR.

My concern was around adding a prop called "hidden" to a component called VisuallyHidden, it would be confusing. I think a goal would be trying to keep the component relatively simple.

make sure VisuallyHidden glues blocks-gallery-caption on top of any className it receives.

I remember considering this, attaching passed classnames, but I think it might conflict with what VisuallyHidden is trying to do. For example, if a passed class sets a display: inline-block or other similar value it could overwrite the components styles. I think my thought was that any additional class shouldn't be needed since the item is going to be hidden, we don't need styling from anywhere else.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] UI Components Impacts or related to the UI component system Good First Issue An issue that's suitable for someone looking to contribute for the first time Needs Dev Ready for, and needs developer efforts
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants