-
Notifications
You must be signed in to change notification settings - Fork 732
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
Build flexible and accessible accordion component #11087
Conversation
Build Artifacts
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did some keyboard nav testing and it seems like it's working relatively well, but perhaps we ought to be sure that we're showing the outline on the heading for the AccordionItem.
Currently, the highlight will go from Checkbox to invisible then on to the arrow KIconButton, then to the next row. Looking at the w3 example it appears that the text that would be read by a screen reader ought to also be outlined/highlighted.
Overall - this is excellent work. I know that things get squirrely with the slots and you've got things hooked up very well here. Thank you for your patience working through it all! Look forward to wrapping it up together next week.
(PS I think you need to rebase on develop to resolve the conflicts)
}, | ||
data() { | ||
return { | ||
itemIds: [], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we ought to call this expandedItemIds
to make clear what we're tracking here
if (this.itemIds.includes(id)) { | ||
return true; | ||
} else { | ||
return false; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Non-blocking style note - you can also just be return this.itemIds.includes(id)
since you're returning a Boolean here.
isOptionSelected(optionId) { | ||
const index = this.itemIds.indexOf(optionId); | ||
if (index === -1) { | ||
this.optionsIdList.push(optionId); | ||
} else { | ||
this.optionsIdList.splice(optionId); | ||
} | ||
}, | ||
isAnswerSelected(optionId) { | ||
if (this.optionsIdList.includes(optionId)) { | ||
return true; | ||
} else { | ||
return false; | ||
} | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This kind of logic should live outside of the Accordion altogether. Not all uses of the Accordion will have the check boxes. This is something that will need to be managed by whatever component is making use of the Accordion.
|
||
<template | ||
v-if="isItemExpanded(item.id)" | ||
#content="" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need for the =""
here - this is just to indicate what slot the wrapped content will go into in the parent component
<AnswerOption | ||
v-for="answer in item.placeholderAnswers" | ||
:key="answer.id" | ||
:optionId="answer.id" | ||
:isOptionSelected="isOptionSelected" | ||
:isAnswerSelected="isAnswerSelected(answer.id)" | ||
> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm sorry I wasn't clear about this - but the question editing business is not necessary here. We won't be doing any kind of question editing in this pass, so this PR just needs to have the accordion component ready to be fleshed out in a follow-up which will wire up everything in #11088 to here, rendering the questions we get from the DB
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the continued efforts here. I've left a few comments about some Kolibri CSS conventions.
I also added some more complex notes around the a11y for the keyboard focus and how we manage clicks, drags, toggles, etc.
<KGrid class="question-row"> | ||
<KGridItem :layout12="{ span: 6 }"> | ||
<div class="left-column-alignment-style"> | ||
<DragHandle> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One thing I noticed is that this doesn't show the cursor when hovered over. I think we should probably update the DragHandle
component directly so that it has CSS with pointer: cursor
so that we get the hand/pointer rather than the normal mouse arrow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Additionally - the DragHandle
doesn't get a focus outline on it when it is focused.
Take a look at kolibri/plugins/learn/assets/src/views/HybridLearningLessonCard.vue LINE 9/10ish
for an example of how the $coreOutline
styles can be applied to a component.
@@ -223,4 +444,55 @@ | |||
text-align: left; | |||
} | |||
|
|||
.left-column-alignment-style { | |||
display: inline-flex; | |||
margin-left: 35px; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We typically try to keep our spacing units in measures of 8px and suggest using em
where 1em = 16px
as a rule of thumb. So typically we should see values like 0.5em, 1em, 1.5em, etc
.
I was looking here because I think the DragHandle should have a bit more space between it and the content to the right of it, so two things to note here:
- Convert uses of px to the em value OR to a px value that is a multiple of 8px
- Ensure that there is enough space between the DragHandle and the content so that there is no overlap of the keyboard-mode outline
<div | ||
v-for="item in placeholderList" | ||
:key="item.id" | ||
> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One thing that came to mind while testing was whether or not keyboard nav focus should cycle through each piece to get to the >
KIconButton to open it so I went and tested the W3 example and noticed that the focus flow goes like:
w3accordionkeyboardnav.mp4
However, ours instead of highlighting the whole "header" bit, goes into the children of the row (drag handle -> checkbox -> open/close icon).
Our situation is a bit different because we have interactions within the heading (drag/checkbox) whereas the example above only has text.
This is a little bit of a pickle... because we also want clicking anywhere on the header to toggle open/close and not just the iconbutton - in fact, I think that that KIconButton should really just be a KIcon. BUT the issue might be in that when you click to select a KCheckbox, you'll also end up clicking to trigger the toggle open/close.
For follow up here I think that maybe the next step is to test out what a @click
handler here might work okay without getting triggered while clicking the drag handle or KCheckbox. We may need to make some decisions based on how that goes. I'll be happy to cohack a bit on this with you as well to see what we can work out.
<KIconButton | ||
v-if="isItemExpanded(item.id)" | ||
class="icon-size" | ||
icon="chevronUp" | ||
@click="toggleItemState(item.id)" | ||
/> | ||
|
||
<KIconButton | ||
v-else | ||
class="icon-size" | ||
icon="chevronRight" | ||
@click="toggleItemState(item.id)" | ||
/> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As noted above - these probably ought to be KIcons assuming we can get everything jiving well w/ focusing/clicking the whole heading element for toggling.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On a separate note I believe KIconButton adds some padding to the icon so you'll probably need to adjust some margin/padding business to align the KIcon here
|
||
<hr class="bottom-border"> | ||
<KButton | ||
style="width:100%;margin-bottom:10px" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My note elsewhere re: typically using 8px increments should also be applied to inline styles in the templates
…s in the accordion panel
It was a bit difficult for me to comment on a single extracted line of code, but I was able to run this branch in development, and actually test some keyboard navigation 😅 Knowing that this is still work in progress, we could maybe postpone resolving all the green ❔ in the recording that indicate that the EQ2.mp4Regarding the missing labels for all the dragging buttons and checkboxes for selection, I already suggested some labels in Slack. This below would be my skeleton version of 2 accordion items, one opened the other closed, sort of a stripped down chimera between the implementation here, and the example on the ARIA APG accordion example. If we add a visually hidden span with additional context, we can use the
|
I would also suggest we disable the dragging with the mouse of accordion items when opened, and enable it only while collapsed. Mostly because questions are bound to have several answers which require panels of certain height, and dragging those elements with a mouse can be a challenge when opened. |
I forgot to add mention for @tomiwaoLE to hear his thoughts about the above ⏫ And I'm also thinking that maybe hearing Open to review and edit is a bit too verbose after every question title... 🤔 |
@radinamatic I'm happy with disabling dragging open question accordions, and enabling only while collapsed. |
Noting after a chat we've decided to try two approaches:
|
Also - one thing to note here is that we should be using the arrows instead of the dragging handle whenever we're in the keyboard modality. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@AllanOXDi I've added some thoughts on how possibly to resolve some open issues and clarified some outcomes of discussions re: the drag/sort functionality.
:isLast="index === placeholderList.length - 1" | ||
@moveUp="shiftOne(index, -1)" | ||
@moveDown="shiftOne(index, +1)" | ||
@click.prevent="toggleItemState(item.id)" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is the source of one issue noted by @radinamatic -- this should be triggering the updating of the order of the items, but not toggling the item state. The "toggleItemState" should isntead be on a button that wraps the whole row (I think the button below around line 210 or so).
See the RearrangeChannelsPage
for an example; there the @sort
event is emitted by the DragContainer
where the new order of the items is handled.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also - I'm having an issue where the drag handle is the only thing being dragged :-/ not sure exactly where the cause of this is by looking at it; but perhaps handling that @sort
event will resolve it.
<button | ||
:id="item.id" | ||
:aria-controls="item.id" | ||
aria-expanded="true" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The value here should be :aria-expanded="isItemExpanded(item.id)"
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Excellent work here Allan. With the feedback above addressed this is ready to merge
Summary
This PR creates a flexible and accessible accordion component to support the enhance quiz managment feature .
closes #11011
References
#11011
Reviewer guidance
See the figma design here
PR process
Reviewer checklist
yarn
andpip
)