Setting the boolean value of aria-expanded using React Hooks - javascript

I'm currently working on accessibility in a web application using React & Ant Design's Select component. aria-expanded is set to false string.
I want to use React useState to toggle aria-expanded="false" so that the aria label in the screen reader can read back wether the dropdown is open or closed.
The idea is to take the default state and use it in the useState hook like this:
const [selectAria, setSelectAria] = useState('false');
<Select
name="someName"
id="someID"
onSelect={(value) => handleChangeSelect(value)}
aria-label={
selectAria ? 'i am closed' : 'i am open '
}
aria-expanded={selectAria}
>
The screen reader is only able to recognize when the initial state. After I select an option, and the dropdown is closed, it does not read back the new state.
Is it possible to do this in React hooks? Is it possible to access the aria-expanded attribute in useState along with the boolean value? I haven't worked on advanced accessibility and have to stick with the antD library for this. Thanks in advance.

In Ant Design, they have provided a bunch of props with very simple names to get our things done in a very friendly manner.
You can decide the initial openness/closeness of your Select element using defaultOpen prop and, always one-to-one bound openness/closeness using open prop.
Here you want to control the open/close action in always one-to-one bound manner I guess. So your code should be like this!
const [selectAria, setSelectAria] = useState(false);
<Select
name="someName"
id="someID"
onSelect={(value) => handleChangeSelect(value)}
open={selectArea}
>
*Note: Removed your aria-label attribute as well. Refer official AntD documentation for a suitable prop API - Select Component!
**Note: If you use this open prop I mentioned above, it may never allow you to close the panel until your selectAria variable is true. So you have to carefully handle that situation as well!
***Note: This answer is referred to Ant Design version 4.7.3. Select the correct version of documentation before you refer!

Related

Can I use vue-router to data-bind a dropdown's value to a URL's query parameter?

I want to bind a dropdown to a query parameter in the URL, so
when opening /page?dropdown=foo, I want the dropdown to have foo pre-selected
and the other way round: when changing the dropdown's value to bar, to have the URL rewritten into /page?dropdown=bar.
My question now:
Is there an out-of-the-box way to tell vue-router to data-bind this?
Or do I need to do it by hand, so when entering/changing the route, setting the dropdown's value and using a :onchange on the dropdown to call router.replace()?
As far as I know, you can't bind it in the way you are thinking, but for sure there is a manner to achieve that.
On router config, it's possible to set props as true, which means that the route.params will be set as the component props, so dropdown will be set with the value on URL (foo or bar).
Make your component react to changes on prop dropdown, this can solve your first question.
For the second question, I think your approach is correct, using the replace method, which would change the URL, and navigate to it but without adding a new history entry, just replacing it.

How can I have a component control a sibling component in React Native?

I'm a little new to React Native and making an app. There are three components I'm currently concerned with:
AllList.js: A screen comprised of a search bar and a FlatList of RowCard.js instances.
RowCard.js: a custom TouchableHighlight component that displays an item from an API, and currently returns an alert when tapped.
drinkPopup.js: A custom Modal component that needs to take an ID from AllList but be controlled by tapping a RowCard.
I have the list of RowCard instances working, but I need to find a way to make the modal from drinkPopup appear when RowCard is tapped. I'm super confused as to how to approach this, since as far as I know props can only be sent from parent to child.
Any suggestions for how to do this? I've looked around to find answers but the results I've found have just been confusing.
So you need a state that will be accessible by both the drinkPopup and RowCard. The way to go is to keep it in their parent (AllList) and pass it accordingly.
So you Parent should be something like:
const AllList = () => {
const [visibleModalId, setVisibleModalId] = useState(null)
return <>
<RowCard setVisibleModalId={setVisibleModalId}>
<drinkPopup visibleModalId={visibleModalId}>
</>
}
That way you can control the modal from RowCard (by calling setVisibleModalId there) and you also know if the drinkPopup should be visible (because it knows if the visibleModalId is null or not)

Make Material UI Autocomplete get focus programatically

I am working on a project that combines react-datasheet and Material UI Autocomplete to mimic a dropdown inside an Excel cell. The base requirement consists of allowing the user to type in or choose one of the options when the autocomplete gets focus. That is where my problem resides. Because the autocomplete is nested inside a cell, it does not get focus automatically when the parent cell is selected (for example, using the keyboard arrows).
So far, I tried using refs so that I would be able to call .current.focus() using something like the following:
const inputRef = useRef();
useEffect = (() => {
if (selected) {
inputRef.current.focus();
}
}, [selected]);
where selected is a boolean prop that I'm passing from the parent cell to the autocomplete. In other words, I'm trying to somehow make it get focus programatically when selected is true. If you have any tips or ideas to get this to work, or another potential approach I could investigate, I would appreciate it.
EDIT: Here's the component tree as shown in the React Dev Tools. Upon inspecting the autocomplete, it does not expose a focus() method. I see there are inputs down the tree but I am not clear on how I can call focus on them and if that would cause the autocomplete to get focus.
The parent (actually, ancestor) cell component. Here's where I have the selected prop.
The Material UI Autocomplete.
Inputs
#newdev I ran into the same issue and #Dekel's answer here helped solve the mystery: react material ui autocomplete element focus onclick.
TLDR: You need to add the ref to the TextField element in Autocomplete's renderInput prop.

Access another component DOM element from a separated competent in React avoiding to document.getElementById

I have two different components in my React application.One component to display pop up, and other for text search field.
There is no relation(parent-child)between them.
My question is when user clicks pop up message(component), be focused text field in another component.
How can I handle this situation without using document.getElementById?
only using a react a specific way like reactDOM with ref.
Is it possible to handle like that?
Thanks
Find the common parent component, and write a function which updates a state with ref of the element to be focused. Pass down that function as props to the second component.
And use <input ref={r => this.props.func(r)
Now on click of first component you can access this parent state.

React render, change radio button programmatically

I was creating a Dropdown component for React. Inside the dropdown, I have a form of radio group buttons.
<DropdownButton />
<DropdownForm />
In the DropdownButton, I have an state to know if it is open or not. Depends on that, DropdownForm it's hidden or not (using display: none).
The use case is: User selects a radio button, click apply and something happen. However, if user selects some radio button, and mouse out the dropdown (without clicking the apply button), the one that is selected should be the one that I get from the store.
Something like:
render: function () {
...
if(store.getSomeParam() != this.state.someParam && !this.props.isOpen){
someParam = store.getSomeParam()
}
Then the radio buttons are like:
<input checked={someParam == "something"} ... />
It doesn't really work. It re-renders but it doesn't change the button that is checked. I also tried with refs:
this.refs.myInput.getDOMNode().checked = true
But still nothing. Is this a correct behaviour?
The only solution I found so far is not using a css hiding class (display: none). So what I do is that the DropdownButton renders the DropdownForm depending on if it's open or not (so if you close it, you are forcing DropdownForm to unmount). Then when opening again, it is taking the values from the store (getInitialState) and it shows the correct radio button selected. But, I am not sure if this is the best solution and if there is any drawback in unmounting the component instead of just css hiding it.
This probably has nothing to do with React at all.
Most browsers don't validate the value of the checked attribute, but merely if it is there or not: http://jsfiddle.net/7jzm7gvw/
Just set the checked attribute to either true or null:
<input checked={someParam == "something" ? true: null} ... />
TL;DR: You must use the componentDidMount lifecycle method, not render, to work with the rendered dom nodes directly.
I was struggling with this as well, and after doing some online research I figured I might as well look into it for myself. Here's what I came up with:
Use the componentDidMount lifecycle method and update whatever you need to in there. Here's a Pen I used to prototype this, and I think it looks okay: http://codepen.io/gholts/pen/GpWzdb
You could drop this in pretty easily to what your'e working on by just putting a componentDidMount method on your object and doing it there. I used document.getElementById but you could definitely use jQuery or whatever else you wanted in there, as once the component has mounted it's available to DOM selectors.
I'm using this now to update 20 radio button groups (so it has to check a prop for three different states and update accordingly) and it loads instantly.
Hope it helps! I used the ES6 class syntax in my Pen, you should check it out if you have some time to refactor :) It's fun.
EDIT: So I figured it out, I'm a dummy. You don't need to do the whole document.getElementById business that I was doing. Just use your this.refs.whichever.getDOMNode().checked = true and it'll work, so long as you do it in componentDidMount. It works there because there is an actual DOM element on the page at that point.

Categories

Resources