diff --git a/src/components/values/containers/ContainerControl.tsx b/src/components/values/containers/ContainerControl.tsx
index 939fe47cd383e2e9c154cb6f0151893eebb4863e..2d690df919fb2545675a2f458e3cdb8470728b50 100644
--- a/src/components/values/containers/ContainerControl.tsx
+++ b/src/components/values/containers/ContainerControl.tsx
@@ -1,10 +1,12 @@
 import {
+  Box,
   FormControl,
   FormControlProps,
   FormHelperText,
   InputLabel,
   Stack,
   styled,
+  useTheme,
 } from '@mui/material'
 import {FocusEvent, PropsWithChildren, useCallback} from 'react'
 
@@ -13,21 +15,36 @@ import PropsProvider from '../utils/PropsProvider'
 import useProps from '../utils/useProps'
 import ContainerProps, {ControlProps} from './ContainerProps'
 
-const InputLabelWithAdornments = styled(InputLabel)(({theme}) => ({
+const LabelContainer = styled(Box)(({theme}) => ({
+  position: 'absolute',
+  marginTop: theme.spacing(0.5),
+  height: theme.spacing(2),
+  width: '100%',
   display: 'flex',
   flexDirection: 'row',
-  alignItems: 'center',
   flexWrap: 'nowrap',
+  flexFlow: 'flex-start',
+  alignItems: 'center',
+}))
+
+const StaticInputLabel = styled(InputLabel)(() => ({
+  position: 'static', // normal "shrink" will not work anymore but was already disabled
+  transform: 'none', // overrides shrink transformations to help position label actions
+  overflow: 'visible', // otherwise label is clipped for short inputs
   textOverflow: 'ellipsis',
-  overflow: 'visible',
-  '& div:first-of-type': {
-    marginLeft: theme.spacing(1),
-  },
+  fontSize: '0.75rem',
+}))
+
+const LabelActionsContainer = styled(Box)(({theme}) => ({
+  position: 'static',
+  display: 'flex',
+  flexDirection: 'row',
+  alignItems: 'center',
+  '& .MuiIconButton-root': {},
   '& .MuiChip-root': {
-    marginTop: 2,
     marginLeft: theme.spacing(0.5),
+    height: 'fit-content',
   },
-  '& .MuiIconButton-root': {},
 }))
 
 export type ValueFormControlProps = ControlProps &
@@ -48,8 +65,9 @@ export function ValueFormControl({...props}: ValueFormControlProps) {
     edit,
     ...formControlProps
   } = props
-
   const {inputId, editable} = useProps<ContainerProps>()
+  const theme = useTheme()
+
   return (
     <FormControl
       fullWidth={fullWidth}
@@ -60,14 +78,17 @@ export function ValueFormControl({...props}: ValueFormControlProps) {
       {...formControlProps}
     >
       {label && (
-        <InputLabelWithAdornments
-          shrink
-          id={editable ? undefined : inputId && `${inputId}-label`}
-          htmlFor={editable ? inputId || undefined : undefined}
-        >
-          {label}
-          {labelActions}
-        </InputLabelWithAdornments>
+        <LabelContainer>
+          <StaticInputLabel
+            shrink
+            id={editable ? undefined : inputId && `${inputId}-label`}
+            htmlFor={editable ? inputId : undefined}
+            style={{marginLeft: editable ? theme.spacing(1.5) : 0}}
+          >
+            {label}
+          </StaticInputLabel>
+          <LabelActionsContainer>{labelActions}</LabelActionsContainer>
+        </LabelContainer>
       )}
       <Stack direction='row' width='100%'>
         {children}
diff --git a/src/components/values/containers/Value.stories.tsx b/src/components/values/containers/Value.stories.tsx
index 9f4f6befa5cf6cb4d5342f14092824209b0df7ea..00204746b0bb6c43dd8c76d6da34c68bda762dd5 100644
--- a/src/components/values/containers/Value.stories.tsx
+++ b/src/components/values/containers/Value.stories.tsx
@@ -44,6 +44,22 @@ export const InitialWidth: Story = {
   },
 }
 
+export const InitialWidthWithShortValueAndLongLabel: Story = {
+  args: {
+    fullWidth: false,
+    value: 'X',
+    editable: false,
+    label: 'label',
+    labelActions: (
+      <>
+        <Chip label='small' size='small' />
+        <Chip label='medium' size='medium' />
+        <CopyToClipboard />
+      </>
+    ),
+  },
+}
+
 export const FormControl: Story = {
   args: {
     helperText: 'Helper text',
diff --git a/src/pages/groups/GroupEditor.tsx b/src/pages/groups/GroupEditor.tsx
index e6cc1ba2cf230ce332557221a3a7befb90d7548b..98f2db6887c96b428836fb4fb54b25a7e9f9ebbb 100644
--- a/src/pages/groups/GroupEditor.tsx
+++ b/src/pages/groups/GroupEditor.tsx
@@ -32,11 +32,6 @@ export default function GroupEditor({editable = false}) {
                     label: 'group name',
                     editable: editable,
                     value: data.group_name,
-                    component: {
-                      Text: {
-                        variant: 'standard',
-                      },
-                    },
                   },
                   {
                     grow: true,
diff --git a/src/pages/groups/GroupPage.test.tsx b/src/pages/groups/GroupPage.test.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..57108db6327e2b7dd3573ac27d4dd176e9a52099
--- /dev/null
+++ b/src/pages/groups/GroupPage.test.tsx
@@ -0,0 +1,52 @@
+import {screen, waitFor, within} from '@testing-library/react'
+import {expect, it, vi} from 'vitest'
+
+import {GraphResponse} from '../../models/graphResponseModels'
+import * as api from '../../utils/api'
+import {
+  checkRow,
+  importLazyComponents,
+  renderWithRouteData,
+} from '../../utils/test.helper'
+import groupRoute from './groupRoute'
+
+await importLazyComponents(groupRoute)
+
+describe('GroupPage', () => {
+  it('loads and initially renders group editor', async () => {
+    const mockedApi = vi.spyOn(api, 'graphApi')
+    window.history.replaceState(null, '', '/group1')
+    mockedApi.mockResolvedValue({
+      group1: {
+        group_name: 'Group 1',
+        group_id: 'group1',
+        owner: {user_id: 'user0', name: 'User 0', affiliation: 'Uni 0'},
+        members: [
+          {user_id: 'user0', name: 'User 0', affiliation: 'Uni 0'},
+          {user_id: 'user1', name: 'User 1', affiliation: 'Uni 1'},
+          {user_id: 'user2', name: 'User 2', affiliation: 'Uni 2'},
+        ],
+      },
+    } as GraphResponse)
+    await renderWithRouteData(groupRoute)
+    await waitFor(() =>
+      expect(screen.getByLabelText('group name')).toHaveTextContent('Group 1'),
+    )
+
+    expect(screen.getByLabelText('owner')).toHaveTextContent('User 0')
+    expect(screen.getByLabelText('members')).toHaveTextContent('3')
+    expect(screen.getByLabelText('group id')).toHaveTextContent('group1')
+
+    const table = screen.getByRole('table')
+    const rows = within(table).getAllByRole('row')
+    expect(rows).toHaveLength(4)
+    checkRow(
+      rows[0],
+      ['Name', 'User ID', 'Affiliation', 'Role'],
+      'columnheader',
+    )
+    checkRow(rows[1], ['User 0', 'user0', 'Uni 0', 'Owner'])
+    checkRow(rows[2], ['User 1', 'user1', 'Uni 1', 'Member'])
+    checkRow(rows[3], ['User 2', 'user2', 'Uni 2', 'Member'])
+  })
+})
diff --git a/src/pages/groups/GroupsPage.tsx b/src/pages/groups/GroupsPage.tsx
index 04b4f878e9031e9e1434561a1c5c12cff51f9d86..255b01b2659e2423539a4b0beffcff19c2d60fb2 100644
--- a/src/pages/groups/GroupsPage.tsx
+++ b/src/pages/groups/GroupsPage.tsx
@@ -1,7 +1,7 @@
 import useSelect from '../../components/navigation/useSelect'
 import Page, {PageActions} from '../../components/page/Page'
 import GroupsActions from './GroupsActions'
-import {GroupsTable} from './GroupsTable'
+import GroupsTable from './GroupsTable'
 import GroupsTableFilterMenu from './GroupsTableFilterMenu'
 
 export default function GroupsPage() {
diff --git a/src/pages/groups/GroupsTable.test.tsx b/src/pages/groups/GroupsTable.test.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..e1432ef6a565ccc859d91659129129658b525c8a
--- /dev/null
+++ b/src/pages/groups/GroupsTable.test.tsx
@@ -0,0 +1,66 @@
+import {render, screen, within} from '@testing-library/react'
+import {describe, expect, it, vi} from 'vitest'
+
+import GroupsTable from './GroupsTable'
+
+const setPaginate = vi.fn()
+const navigate = vi.fn()
+
+vi.mock('../../components/routing/usePagination', () => ({
+  validatePaginationSearch: () => {},
+  default: () => [
+    {
+      page: 1,
+      per_page: 10,
+      page_size: 12,
+      total: 100,
+    },
+    setPaginate,
+  ],
+}))
+
+vi.mock('../../components/routing/useRoute', () => ({
+  default: () => ({
+    navigate,
+    search: {},
+    url: () => '/',
+    response: Array.from({length: 12}, (_, index) => ({
+      group_id: `group${index}`,
+      group_name: `Group ${index}`,
+      owner: {user_id: `owner${index}`, name: `Owner ${index}`},
+      members: [
+        {user_id: `owner${index}`, name: `Owner ${index}`},
+        {user_id: `member${index}`, name: `Member ${index}`},
+      ],
+    })),
+  }),
+}))
+
+afterEach(() => {
+  vi.restoreAllMocks()
+})
+
+describe('GroupsTable Component', () => {
+  it('should render data, sort by name, request more data', async () => {
+    render(<GroupsTable />)
+
+    const table = screen.getByRole('table')
+    expect(table).toBeVisible()
+
+    const rows = within(table).getAllByRole('row')
+    expect(rows).toHaveLength(13)
+
+    const sortNameButton = screen.getByRole('button', {
+      name: 'Sort by Name ascending',
+    })
+    await sortNameButton.click()
+    expect(setPaginate).toHaveBeenCalledWith({
+      order: 'asc',
+      order_by: 'group_name',
+    })
+
+    const nextPageButton = screen.getByText('Load More')
+    await nextPageButton.click()
+    expect(setPaginate).toHaveBeenCalledWith({page_size: 12 + 50})
+  })
+})
diff --git a/src/pages/groups/GroupsTable.tsx b/src/pages/groups/GroupsTable.tsx
index 9f7fd2db0a22e1635ac8f494ab59d3abdbf56173..8b53791161a216793fcdfa69e72257842bcf180a 100644
--- a/src/pages/groups/GroupsTable.tsx
+++ b/src/pages/groups/GroupsTable.tsx
@@ -20,7 +20,7 @@ function getUserRole(group: GroupResponse, userId: string | null | undefined) {
   }
 }
 
-export function GroupsTable() {
+export default function GroupsTable() {
   const {user} = useAuth()
   const {navigate} = useRoute()
   const data = useRouteData(groupsRoute)
diff --git a/src/pages/groups/groupsRoute.tsx b/src/pages/groups/groupsRoute.tsx
index ce44e84a6f5a5b668fbad6f89985a9fbc4d13d0e..7bfdc4806e2efe9d035df5238ff5a984c70ac263 100644
--- a/src/pages/groups/groupsRoute.tsx
+++ b/src/pages/groups/groupsRoute.tsx
@@ -1,5 +1,8 @@
 import {Route} from '../../components/routing/types'
-import {validatePaginationSearch} from '../../components/routing/usePagination'
+import {
+  createPaginationRequest,
+  validatePaginationSearch,
+} from '../../components/routing/usePagination'
 import {GroupsRequest} from '../../models/graphRequestModels'
 import {GroupsResponse} from '../../models/graphResponseModels'
 import {PageBasedPagination} from '../../utils/types'
@@ -26,10 +29,7 @@ const groupsRoute: Route<
     isLeaf
       ? {
           m_request: {
-            pagination: {
-              page: search.page,
-              page_size: search.page_size,
-            },
+            pagination: createPaginationRequest(search),
             query: {
               ...(search.user_id && {user_id: search.user_id}),
             },
diff --git a/src/utils/test.helper.tsx b/src/utils/test.helper.tsx
index 764d737552d94b17dd434b406d9a47a0925c4a64..85fcc2e80b02ae8c24b909a4e484dd65026e30ed 100644
--- a/src/utils/test.helper.tsx
+++ b/src/utils/test.helper.tsx
@@ -1,5 +1,5 @@
 import {ThemeProvider, createTheme} from '@mui/material/styles'
-import {render as rtlRender} from '@testing-library/react'
+import {render as rtlRender, within} from '@testing-library/react'
 import mediaQuery from 'css-mediaquery'
 import React, {ReactElement, ReactNode} from 'react'
 import {vi} from 'vitest'
@@ -84,3 +84,15 @@ const customRender = (ui: ReactElement, options = {}) =>
 // eslint-disable-next-line react-refresh/only-export-components
 export * from '@testing-library/react'
 export {customRender as render}
+
+type tableCellRole = 'cell' | 'columnheader' | 'rowheader'
+
+export const checkRow = (
+  row: HTMLElement,
+  texts: string[],
+  role: tableCellRole = 'cell',
+) => {
+  const cells = within(row).getAllByRole(role)
+  expect(cells).toHaveLength(texts.length)
+  cells.forEach((cell, i) => expect(cell).toHaveTextContent(texts[i]))
+}