Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"changes": [
{
"packageName": "office-ui-fabric-react",
"comment": "Panel: pass ID for header text element to custom renderer",
"type": "minor"
}
],
"packageName": "office-ui-fabric-react",
"email": "elcraig@microsoft.com"
}
16 changes: 11 additions & 5 deletions packages/office-ui-fabric-react/src/components/Panel/Panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ export class Panel extends BaseComponent<IPanelProps, IPanelState> implements IP
const isLeft = type === PanelType.smallFixedNear ? true : false;
const isRTL = getRTL();
const isOnRightSide = isRTL ? isLeft : !isLeft;
const headerTextId = id + '-headerText';
const headerTextId = headerText && id + '-headerText';
const customWidthStyles = (type === PanelType.custom) ? { width: customWidth } : {};

if (!isOpen && !isAnimating && !isHiddenOnDismiss) {
Expand All @@ -122,11 +122,13 @@ export class Panel extends BaseComponent<IPanelProps, IPanelState> implements IP
);
}

const header = onRenderHeader(this.props, this._onRenderHeader, headerTextId);

return (
<Layer { ...layerProps }>
<Popup
role='dialog'
ariaLabelledBy={ headerText && headerTextId }
ariaLabelledBy={ header ? headerTextId : undefined }
onDismiss={ this.dismiss }
className={
css(
Expand Down Expand Up @@ -181,7 +183,7 @@ export class Panel extends BaseComponent<IPanelProps, IPanelState> implements IP
{ onRenderNavigation(this.props, this._onRenderNavigation) }
</div>
<div className={ css('ms-Panel-contentInner', styles.contentInner) } >
{ onRenderHeader(this.props, this._onRenderHeader) }
{ header }
{ onRenderBody(this.props, this._onRenderBody) }
{ onRenderFooter(this.props, this._onRenderFooter) }
</div>
Expand Down Expand Up @@ -252,7 +254,11 @@ export class Panel extends BaseComponent<IPanelProps, IPanelState> implements IP
return null;
}

private _onRenderHeader = (props: IPanelProps): JSX.Element | null => {
private _onRenderHeader = (
props: IPanelProps,
defaultRender?: (props?: IPanelProps) => JSX.Element | null,
headerTextId?: string | undefined
): JSX.Element | null => {
const {
headerText,
headerClassName = '',
Expand All @@ -263,7 +269,7 @@ export class Panel extends BaseComponent<IPanelProps, IPanelState> implements IP
<div className={ css('ms-Panel-header', styles.header) }>
<p
className={ css('ms-Panel-headerText', styles.headerText, headerClassName) }
id={ this.state.id + '-headerText' }
id={ headerTextId }
role='heading'
>
{ headerText }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ export interface IPanelProps extends React.Props<Panel> {
/**
* Optional custom renderer for header region. Replaces current title
*/
onRenderHeader?: IRenderFunction<IPanelProps>;
onRenderHeader?: IPanelHeaderRenderer;

/**
* Optional custom renderer for body region. Replaces any children passed into the component.
Expand All @@ -176,6 +176,27 @@ export interface IPanelProps extends React.Props<Panel> {
componentId?: string;
}

/**
* Renderer function which takes an additional parameter, the ID to use for the element containing
* the panel's title. This allows the `aria-labelledby` for the panel popup to work correctly.
* Note that if `headerTextId` is provided, it **must** be used on an element, or screen readers
* will be confused by the reference to a nonexistent ID.
*/
export interface IPanelHeaderRenderer extends IRenderFunction<IPanelProps> {
/**
* @param props Props given to the panel
* @param defaultRender Default header renderer. If using this renderer in code that does not
* assign `headerTextId` to an element elsewhere, it **must** be passed to this function.
* @param headerTextId If provided, this **must** be used as the ID of an element containing the
* panel's title, because the panel popup uses this ID as its aria-labelledby.
*/
(
props?: IPanelProps,
defaultRender?: IPanelHeaderRenderer,
headerTextId?: string | undefined
): JSX.Element | null;
}

export enum PanelType {
/**
* Renders the panel in 'small' mode, anchored to the far side (right in LTR mode), and has a fluid width.
Expand Down