|
102 | 102 | <p class="stacks-copy"> |
103 | 103 | In most cases, validation states shouldn’t be shown until after the user has submitted the form. There are certain exceptions where it can be appropriate to show a validation state without form submission—after a sufficient delay. For example, validating the existence of a username can occur after the user has stopped typing, or when they’ve deselected the input. |
104 | 104 | </p> |
105 | | - <p class="stacks-copy mb32"> |
| 105 | + <p class="stacks-copy"> |
106 | 106 | Once the user is presented validation states, they can be cleared as soon as the user interacts with the form field. For example, the error state for an incorrect password should be cleared as soon as the user focuses the input to re-enter their password. |
107 | 107 | </p> |
| 108 | + <p class="stacks-copy mb32"> |
| 109 | + Similarly to using <code class="stacks-code">for</code> with labels, validation messages below inputs should be associated with their respective fields using the <code class="stacks-code">aria-describedby</code> attribute for accessible behavior. |
| 110 | + </p> |
108 | 111 |
|
109 | 112 | {% header "h3", "Validation examples" %} |
110 | 113 | {% header "h4", "Warning" %} |
|
113 | 116 | <div class="d-flex gs4 gsy fd-column has-warning"> |
114 | 117 | <label class="flex--item s-label" for="example-warning">Username</label> |
115 | 118 | <div class="d-flex ps-relative"> |
116 | | - <input class="s-input" id="example-warning" type="text" placeholder="" /> |
| 119 | + <input class="s-input" id="example-warning" type="text" placeholder="" aria-describedby="example-warning-desc" /> |
117 | 120 | @Svg.Alert.With("s-input-icon") |
118 | 121 | </div> |
119 | | - <p class="flex--item s-input-message">Caps lock is on! <a>Having trouble entering your username?</a></p> |
| 122 | + <p id="example-warning-desc" class="flex--item s-input-message">Caps lock is on! <a>Having trouble entering your username?</a></p> |
120 | 123 | </div> |
121 | 124 | {% endhighlight %} |
122 | 125 | <div class="stacks-preview--example"> |
123 | 126 | <div class="flex--item"> |
124 | 127 | <div class="d-flex gs4 gsy fd-column has-warning"> |
125 | 128 | <label class="flex--item s-label" for="example-warning">Username</label> |
126 | 129 | <div class="d-flex ps-relative"> |
127 | | - <input class="s-input" id="example-warning" type="text" value="AA" /> |
| 130 | + <input class="s-input" id="example-warning" type="text" value="AA" aria-describedby="example-warning-desc" /> |
128 | 131 | {% icon "Alert", "s-input-icon" %} |
129 | 132 | </div> |
130 | | - <p class="flex--item s-input-message">Caps lock is on! <a>Having trouble entering your username?</a></p> |
| 133 | + <p id="example-warning-desc" class="flex--item s-input-message">Caps lock is on! <a>Having trouble entering your username?</a></p> |
131 | 134 | </div> |
132 | 135 | </div> |
133 | 136 | </div> |
134 | 137 | </div> |
135 | 138 |
|
136 | 139 | {% header "h4", "Error" %} |
| 140 | + {% tip, "warning", "mb24" %} |
| 141 | + <p class="mb0">In addition to using the "error" state for a field, be sure to use the <a href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_aria-invalid_attributev"><code class="stacks-code">aria-invalid</code></a> attribute to indicate to assistive technology that respective fields have failed validation.</p> |
| 142 | + {% endtip %} |
| 143 | + |
137 | 144 | <div class="stacks-preview"> |
138 | 145 | {% highlight html %} |
139 | 146 | <div class="d-flex gs4 gsy fd-column has-error"> |
140 | | - <label class="flex--item s-label" for="example-warning">Username</label> |
| 147 | + <label class="flex--item s-label" for="example-error">Username</label> |
141 | 148 | <div class="d-flex ps-relative"> |
142 | | - <input class="s-input" id="example-warning" type="text" placeholder="e.g. johndoe111" /> |
| 149 | + <input class="s-input" id="example-error" type="text" placeholder="e.g. johndoe111" aria-describedby="example-error-desc" aria-invalid="true" /> |
143 | 150 | @Svg.AlertCircle.With("s-input-icon") |
144 | 151 | </div> |
145 | | - <p class="flex--item s-input-message">You must provide a username. <a>Forgot your username?</a></p> |
| 152 | + <p id="example-error-desc" class="flex--item s-input-message">You must provide a username. <a>Forgot your username?</a></p> |
146 | 153 | </div> |
147 | 154 | {% endhighlight %} |
148 | 155 | <div class="stacks-preview--example"> |
149 | 156 | <div class="flex--item"> |
150 | 157 | <div class="d-flex gs4 gsy fd-column has-error"> |
151 | 158 | <label class="flex--item s-label" for="example-error">Username</label> |
152 | 159 | <div class="d-flex ps-relative"> |
153 | | - <input class="s-input" id="example-error" type="text" /> |
| 160 | + <input class="s-input" id="example-error" type="text" aria-describedby="example-error-desc" /> |
154 | 161 | {% icon "AlertCircle", "s-input-icon" %} |
155 | 162 | </div> |
156 | | - <p class="flex--item s-input-message">You must provide a username. <a>Forgot your username?</a></p> |
| 163 | + <p id="example-error-desc" class="flex--item s-input-message">You must provide a username. <a>Forgot your username?</a></p> |
157 | 164 | </div> |
158 | 165 | </div> |
159 | 166 | </div> |
|
163 | 170 | <div class="stacks-preview"> |
164 | 171 | {% highlight html %} |
165 | 172 | <div class="d-flex gs4 gsy fd-column has-success"> |
166 | | - <label class="flex--item s-label" for="example-warning">Username</label> |
| 173 | + <label class="flex--item s-label" for="example-success">Username</label> |
167 | 174 | <div class="d-flex ps-relative"> |
168 | | - <input class="s-input" id="example-warning" type="text" /> |
| 175 | + <input class="s-input" id="example-success" type="text" aria-describedby="example-success-desc" /> |
169 | 176 | @Svg.Checkmark.With("s-input-icon") |
170 | 177 | </div> |
171 | | - <p class="flex--item s-input-message">That name is available! <a>Why do we require a username?</a></p> |
| 178 | + <p id="example-success-desc" class="flex--item s-input-message">That name is available! <a>Why do we require a username?</a></p> |
172 | 179 | </div> |
173 | 180 | {% endhighlight %} |
174 | 181 | <div class="stacks-preview--example"> |
175 | 182 | <div class="flex--item"> |
176 | 183 | <div class="d-flex gs4 gsy fd-column has-success"> |
177 | 184 | <label class="flex--item s-label" for="example-success">Username</label> |
178 | 185 | <div class="d-flex ps-relative"> |
179 | | - <input class="s-input" id="example-success" type="text" value="aaronshekey" /> |
| 186 | + <input class="s-input" id="example-success" type="text" value="aaronshekey" aria-describedby="example-success-desc" /> |
180 | 187 | {% icon "Checkmark", "s-input-icon" %} |
181 | 188 | </div> |
182 | | - <p class="flex--item s-input-message">That name is available! <a>Why do we require a username?</a></p> |
| 189 | + <p id="example-success-desc" class="flex--item s-input-message">That name is available! <a>Why do we require a username?</a></p> |
183 | 190 | </div> |
184 | 191 | </div> |
185 | 192 | </div> |
|
0 commit comments