Adding Alt Text to your Images in Optimizely
When developing a site using Optimizely, it is important to keep accessibility in mind. A common solution that I’ve found helpful is to extend the ImageData class from EpiServer.Core and add a property for Alt Text. This concept is demonstrated in the Alloy Project and has been explained further in the blog post ‘Episerver and Alternate Text for Images in the TinyMCE Rich Text Editor‘ by Dylan McCurry.
Problem with Tiny MCE’s Rich Text Editor
Following the blog post mentioned above, we can now correctly render the Alt Text from each ImageFile in an XhtmlString. When testing this you’ll notice that the CMS still warns the user to ‘input a more meaningful alt-text’. To fix this we can disable TinyMCE’s alt text validation and write a custom Validator that will consider the Alt Text added to our Image class.
Disabling TinyMCE Validation
Before creating our validator, we should first remove the default validation behavior from TinyMCE. Simply call the helper method DisableValidation(true) in your project’s Startup.cs or refer to Optimizely’s documentation if you haven’t already configured TinyMCE.
services.Configure<TinyMceConfiguration>(config => { config.Default() ... .DisableValidation(true); });
Adding Custom Alt Text Validation to XhtmlString
There are two main options to choose from when adding validation to a property: creating an Attribute or a Validator. In our case, we will want to use a Validator rather than an Attribute since it will automatically apply our validation logic to all instances of XhtmlString without the need to add the Attribute to each property definition.
public class XhtmlStringValidator : IValidate<XhtmlString> { private static readonly IContentLoader contentLoader = ServiceLocator.Current.GetInstance<IContentLoader>(); private static IList<String> GetImagesWithoutAltText(){...} public IEnumerable<ValidationError> Validate(XhtmlString html) { var imageNames = GetImagesWithoutAltText(html); if (images.Count > 0) { return new[] { new ValidationError { ErrorMessage = $"Add alt text to the following images embedded in the Rich Text Editor: {string.Join(", ", images)}.", Severity = ValidationErrorSeverity.Error, ValidationType = ValidationErrorType.AttributeMatched } }; } return Enumerable.Empty<ValidationError>(); } } }
Simply create a new class implementing the IValidator interface and pass it the type XhtmlString, no other registration is required. Within this class will need to implement the Validate function which will return an IEnumerable of validation errors and is called before content is saved. You can choose whether or not to raise a Warning (does not prevent publish) or an Error (prevents publish) by setting the Severity on the ValidationError. Simply returning an empty Enumerable will indicate that the property is valid.
private static IList<String> GetImagesWithoutAltText(XhtmlString xhtmlString) { var images = new List<string>(); foreach (var urlFragment in xhtmlString.Fragments.Where(x => x is UrlFragment)) { foreach (var guid in urlFragment.ReferencedPermanentLinkIds) { if(!contentLoader.TryGet(guid, out ImageFile image)) { continue; } if (string.IsNullOrEmpty(image.AltText)) { images.Add(image.Name); } } } return images; }
The logic of the validator locates each image in the RTE by looping through the XhtmlString Fragments and attempting to load the content as ImageFile via the GUIDs stored in RefrencedPermanentLinkIds. After loading each image we check if the alt text is defined, and if it is null or empty, we store that image’s name on a list that’s used to create the error message displayed within the CMS.
Results
With the TinyMCE validation disabled and our own Validator created, we should now accurately validate whether or not a Content Author has defined all Alt Text values on the images embedded in a Rich Text field.
I hoped blog has helped you create a more accessible site and a better CMS experience!