Skip to content

[RFC] Refs in v4 #14415

@eps1lon

Description

@eps1lon

refs in v3

  1. refs are not included in the API documentation on material-ui.com
  2. type declarations forbid ref e.g. <Button ref={handleRef} /> but allow innerRef for every component
    • The latter is wrong in some cases. E.g. The inner components of Paper or Backdrop are function components and can therefore not hold refs. It will trigger a runtime warning.
  3. withStyles from @material-ui/core does not forward refs from ref but innerRef.
    • named props for refs can be problematic if multiple HOCs are used. E.g. Using styled-components to style material-ui components will prevent innerRef from being passed to the inner material-ui component.

Proposal

explicitly document ref

Couple of alternatives:

  1. We could start by collecting what components allow this at the moment (basically every component wrapped in withStyles). This will break in v4 if [styles] Improve ref forwarding #13676 is accepted
  2. Disallow ref on all of our components. If the DOM node is required RootRef should be used.

The type declarations follow from the documentation.

ref in v4

With #13676 and the replacement of @material-ui/core/styles with @material-ui/styles as our internal styling solution <Button ref /> would return the ref to the inner component by default. In it's current state some components would loose the ability to hold ref (e.g. AppBar).

There is an argument to be made that ref inherently cause all sorts of problems in general. However I would argue that all of our components return some html element. Interfacing our components so that they only return a ref to an abstract HTMLElement should therefore cause no problems in the future. It doesn't bind us to any specific implementation (other than a html element). This allows e.g. layout computations if necessary or imperative focus which is what we use internally.

I'm in favor of enabling refs on all of our existing components. It allows for a simpler API where one doesn't have to look at the API docs for every single component and check if it allows ref (and then be annoyed because we didn't have your use case in mind). (Although TS users can be lazy and don't have to check API docs).

Summary

  1. Add explicit documentation
  2. Fix typescript declarations
  3. One of
    1. Disallow ref on all components i.e. use ref at your own risk. Prefer RootRef if you need the DOM node
      • RootRef will trigger findDOMNode deprecation warnings
    2. Don't change ref behavior for inner components. ref behavior on actual component will change though with [styles] Improve ref forwarding #13676.
      • users are stuck with findDOMNode
    3. Allow ref on all components. Interface it as a abstract HTMLElement
      • strict and concurrent mode viable for all current use cases

Confirmed

Currently missing (strike through means not applicable, some might already work but are not picked up by our docs generator)
  • AppBar.js
  • Backdrop.js
  • Avatar.js
  • BottomNavigation.js
  • BottomNavigationAction.js
  • Breadcrumbs.js
  • [ ] TouchRipple.js (need imperative handle)
  • Card.js
  • CardActionArea.js
  • CardActions.js
  • CardContent.js
  • CardHeader.js
  • CardMedia.js
  • Checkbox.js
  • CircularProgress.js
  • [ ] ClickAwayListener.js no host component rendered
  • Container.js
  • [ ] CssBaseline.js no host component rendered
  • Dialog.js
  • DialogActions.js
  • DialogContent.js
  • DialogContentText.js
  • DialogTitle.js
  • Divider.js
  • ExpansionPanel.js
  • ExpansionPanelActions.js
  • ExpansionPanelDetails.js
  • ExpansionPanelSummary.js
  • Fab.js
  • [ ] Fade.js no host component rendered
  • FilledInput.js
  • FormControl.js
  • FormControlLabel.js
  • FormGroup.js
  • FormHelperText.js
  • FormLabel.js
  • Grid.js
  • GridList.js
  • GridListTile.js
  • GridListTileBar.js
  • [ ] Grow.js no host component rendered
  • [ ] Hidden.js no host component rendered
  • Icon.js
  • IconButton.js
  • Input.js
  • InputAdornment.js
  • InputLabel.js
  • Link.js
  • List.js
  • ListItem.js
  • [ ] ListItemAvatar.js no host component rendered
  • ListItemIcon.js
  • ListItemSecondaryAction.js
  • ListItemText.js
  • ListSubheader.js
  • Menu.js
  • MenuItem.js
  • MenuList.js
  • MobileStepper.js
  • NativeSelect.js
  • [ ] NoSsr.js no host component rendered
  • OutlinedInput.js
  • Paper.js
  • Popper.js
  • [ ] Portal.js no host component rendered
  • Radio.js
  • RadioGroup.js
  • [ ] RootRef.js no host component rendered
  • Select.js
  • SnackbarContent.js
  • Step.js
  • StepButton.js
  • StepConnector.js
  • StepContent.js
  • StepIcon.js
  • StepLabel.js
  • Stepper.js
  • SvgIcon.js
  • Switch.js
  • Tab.js
  • Table.js
  • TableBody.js
  • TableCell.js
  • TableFooter.js
  • TableHead.js
  • TableRow.js
  • TableSortLabel.js
  • TextField.js
  • Toolbar.js
  • Typography.js
  • [ ] Zoom.js no host component rendered
  • Badge.js
  • Button.js
  • Collapse.js
  • Drawer.js
  • LinearProgress.js
  • [ ] Slide.js no host component rendered
  • Snackbar.js
  • TablePagination.js
  • [ ] Tooltip.js Renders children as root, PopperProps available
  • ButtonBase.js
  • Chip.js
  • InputBase.js
  • Modal.js
  • SwipeableDrawer.js
  • Tabs.js
  • Popover.js
  • [ ] SpeedDialIcon.js lab has low priority
  • [ ] Slider.js lab has low priority
  • [ ] SpeedDialAction.js lab has low priority
  • [ ] SpeedDial.js lab has low priority
  • [ ] ToggleButton.js lab has low priority
  • [ ] ToggleButtonGroup.js lab has low priority

Resources

/cc @mui-org/core-contributors

Metadata

Metadata

Assignees

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions