primefaces / primefaces/primereact

Core: Right To Left (RTL) Support

Open
#3,096 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Component: RTL Type: Enhancement
Dominant language
CSS
Stars
8.3k
Forks
1.2k
PR merge metrics
No merged PRs in 30d

Description

Describe the feature you would like to see added

Right To Left support is not currently fully supported in PrimeReact. From PrimeTek:

We are currently only considering doing a study on PrimeReact. PrimeReact has modern CSS styles and this kind of improvement will indeed be easier than we expected. However, we cannot say the same for PrimeFaces. As you know, PrimeFaces is a proven 10-year project. We work every day to improve existing CSS styles. In the long run, of course, we plan to make improvements to PrimeFaces for RTL. Unfortunately, I can't give an exact date for now.

Issues opened previously:

Describe the feature you would like to see added

Improve CSS, so that components are rendered automatically and appropriately for right to left languages. This will require changes in:

  • Themes - for cases like where the buttons, spinners, etc. are positioned within respective widgets
  • PrimeFlex - for things like left/right margins and paddings
  • PrimeIcons - for icons, that represent some kind of arrow pointing left or right
  • Markup changes within PrimeReact, PrimeNg, etc. could probably avoided
Is your feature request related to a problem?

No response

Describe the solution you'd like

I think the best way is to use [dir='rtl'] in the CSS selectors and address the specific cases where left/right attributes are affected.

Describe alternatives you have considered

What I tried (and it worked well, but not perfect) is to include some additional CSS rules, as per the below example. You can observe the results in this Storybook https://master--626d34151d5489004a1c5228.chromatic.com/?path=/story/form--table-ar

import { createUseStyles } from 'react-jss';

const useStyles = createUseStyles({
    '@global': {
        html: {
            "&[dir='rtl']": {
                '& .left-0.right-0': {
                    left: '0px !important',
                    right: '0px !important'
                },
                '& .right-0': {
                    left: '0px !important',
                    right: 'unset !important'
                },
                '& .left-0': {
                    left: 'unset !important',
                    right: '0px !important'
                },
                '& .p-float-label > label': {
                    left: 'unset !important',
                    right: 'var(--inline-spacing)'
                },
                '& .mr-2': {
                    marginLeft: 'var(--inline-spacing) !important',
                    marginRight: 'unset !important'
                },
                '& .p-button-icon-left': {
                    marginLeft: 'var(--inline-spacing)',
                    marginRight: 'initial'
                },
                '& .pi-angle-double-left:before': {
                    content: '"\\e92e"'
                },
                '& .pi-angle-left:before': {
                    content: '"\\e932"'
                },
                '& .pi-angle-double-right:before': {
                    content: '"\\e92d"'
                },
                '& .pi-angle-right:before': {
                    content: '"\\e931"'
                },
                '& .p-datatable .p-datatable-tbody > tr > td': {
                    textAlign: 'right'
                },
                '& .p-calendar-w-btn-right .p-datepicker-trigger, & .p-buttonset .p-button:last-of-type': {
                    borderTopLeftRadius: 'var(--border-radius)',
                    borderBottomLeftRadius: 'var(--border-radius)',
                    borderTopRightRadius: '0px',
                    borderBottomRightRadius: '0px'
                },
                '& .p-calendar-w-btn-right .p-inputtext, & .p-inputnumber-buttons-stacked .p-inputnumber-input, & .p-buttonset .p-button:first-of-type': {
                    borderTopLeftRadius: '0px',
                    borderBottomLeftRadius: '0px',
                    borderTopRightRadius: 'var(--border-radius)',
                    borderBottomRightRadius: 'var(--border-radius)'
                },
                '& .p-inputnumber-buttons-stacked .p-button.p-inputnumber-button-up': {
                    borderTopLeftRadius: 'var(--border-radius)',
                    borderBottomLeftRadius: '0px',
                    borderTopRightRadius: '0px',
                    borderBottomRightRadius: '0px'
                },
                '& .p-inputnumber-buttons-stacked .p-button.p-inputnumber-button-down': {
                    borderTopLeftRadius: '0px',
                    borderBottomLeftRadius: 'var(--border-radius)',
                    borderTopRightRadius: '0',
                    borderBottomRightRadius: '0px'
                },
                '& .p-treeselect-close, & .p-multiselect-panel .p-multiselect-header .p-multiselect-close': {
                    marginLeft: 'initial',
                    marginRight: 'auto'
                },
                '& .p-tree .p-treenode-children': {
                    padding: '0 var(--content-padding) 0 0'
                },
                '& .p-multiselect-panel .p-multiselect-items .p-multiselect-item .p-checkbox, & .p-multiselect.p-multiselect-chip .p-multiselect-token, & .p-treeselect.p-treeselect-chip .p-treeselect-token, & .p-tabmenu .p-tabmenu-nav .p-tabmenuitem .p-menuitem-link .p-menuitem-icon': {
                    marginLeft: 'var(--inline-spacing)',
                    marginRight: '0px'
                },
                '& .p-multiselect.p-multiselect-chip .p-multiselect-token .p-multiselect-token-icon, & .p-chips .p-chips-multiple-container .p-chips-token .p-chips-token-icon, & .p-menubar-root-list > .p-menuitem > .p-menuitem-link .p-submenu-icon': {
                    marginLeft: '0px',
                    marginRight: 'var(--inline-spacing)'
                },
                '& .p-multiselect .p-multiselect-clear-icon': {
                    right: 'inherit',
                    left: '2.357rem'
                },
                '& ul.p-submenu-list': {
                    left: 0,
                    right: 'initial!important'
                },
                '& .p-buttonset .p-button:not(:last-child)': {
                    borderLeft: '0 none',
                    borderRight: '1px solid var(--surface-border)',
                    '&.p-highlight': {
                        borderColor: 'var(--primary-color)'
                    }
                },
                '& .pi-chevron-right, & .pi-chevron-left': {
                    rotate: '180deg'
                },
                '& .pi-caret-right:before': {
                    content: '"\\e904"'
                },
                '& .pi-caret-left:before': {
                    content: '"\\e905"'
                },
                '& .pi-arrow-right:before': {
                    content: '"\\e91a"'
                },
                '& .pi-arrow-left:before': {
                    content: '"\\e91b"'
                }
            }
        }
    }
});
Additional context

While my solution worked, it does not feel right. Let me know if you are interested in including RTL support in the libraries. I can help with ideas and also with providing proper Arabic translations to test with.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reviewing the linked Carousel, Dropdown, SideBar, FloatLabel, ContextMenu, Datatable, Menu, and PanelMenu issues, along with the provided RTL Storybook example. Inspect the theme, PrimeFlex, and PrimeIcons areas for the listed left/right cases; done means the affected components render appropriately under dir='rtl' across the identified cases.

Written by the indexing model from the issue text.

Assessment

Tech stack
css, react
Domain
design, frontend, internationalization
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.