Search code examples
reactjstailwind-cssnextuitailwind-css-3

How to customize HeroUI Table header when isHeaderSticky prop applied?


Using (Vite + ReactJS + Tailwind CSS v3 + HeroUI)

If we applied isHeaderSticky prop on a HeroUI Table, it would add another style like some kind of shadow or outline or maybe sort of border, how can we remove that?

enter image description here

My code to produce the picture above is:

  <Table
    removeWrapper
    isHeaderSticky                    
    classNames={{ 
      th: ["!rounded-none", "!shadow-none", "!border-none"],          
    }}
    >
    <TableHeader>
      <TableColumn key="name">NAME</TableColumn>
      <TableColumn key="role">ROLE</TableColumn>
      <TableColumn key="status">STATUS</TableColumn>
    </TableHeader>
    <TableBody items={items} emptyContent={"No permits found"}>              
    </TableBody>
  </Table>

I tried to add this:

classNames={{
  th: ["!border-none", "!rounded-none", "!shadow-none"],
}}

but it's not working, so any idea please?


Solution

  • I checked the isHeaderSticky example in the HeroUI documentation, which is a working reproduction. This allowed me to see how HeroUI styled the thead.

    <thead class="[&amp;>tr]:first:rounded-lg sticky top-0 z-20 [&amp;>tr]:first:shadow-small" role="rowgroup">
      <tr role="row" class="group/tr outline-none data-[focus-visible=true]:z-10 data-[focus-visible=true]:outline-2 data-[focus-visible=true]:outline-focus data-[focus-visible=true]:outline-offset-2">
        ...
      </tr>
    </thead>
    

    So, the first tr children in the thead receive the shadow-small class. The first tr itself doesn't get an outline, only in focus mode. So, I just need to remove the shadow from the thead element.

    Let's see how I can implement classes in the thead. The <Table> component, as you mentioned in the question, has a classNames attribute that accepts an array with the key thead alongside th.

    classNames: Partial<Record<'base' | 'table' | 'thead' | 'tbody' | 'tfoot' | 'emptyWrapper' | 'loadingWrapper' | 'wrapper' | 'tr' | 'th' | 'td' | 'sortIcon', string>>
    
    // prettier format
    classNames: {
      base: "...",
      table: "...",
      thead: "...",
      // etc.
    }
    

    Let's pass it:

    <Table
      removeWrapper
      isHeaderSticky                    
      classNames={{
        thead: "[&>tr]:first:shadow-none", // or can use [&>tr]:first:!shadow-none    
      }}
    >
      ...
    </Table>
    

    result

    The shadow-none passed to the tr could work, but for the th (as you mentioned in the question), it's definitely not suitable, because the shadow is applied to thead > tr:first.

    The most accurate solution would be to tell the thead that the first tr inside it shouldn't receive a shadow.

    classNames={{
      thead: "[&>tr]:first:shadow-none", // this will be true only to thead > tr:first
    }}
    

    Alternatively, applying first:shadow-none to the tr might work, but this would not only remove the shadow from thead > tr:first, but also from, for example, tbody > tr:first.

    classNames={{
      tr: "first:shadow-none", // this will be true to thead > tr:first, but also will be true to tbody > tr:first
    }}