docs
    re-site-kit: Styling and performance
    v0.6.0.md

    Styling and performance

    The components come unstyled apart from a few layout essentials, with a stable class on every element so your site's CSS can make them its own. This page lists every class hook, explains the inline styles, and covers what keeps listing pages fast.

    Class hooks

    Every component also accepts a className, added next to its root class.

    ListingCard and ListingGrid

    ClassElement
    re-listing-gridThe grid container
    re-listing-card__linkThe <a> around a card, when it has a link
    re-listing-cardThe card
    re-listing-card__mediaThe photo frame
    re-listing-card__imageThe photo
    re-listing-card__priceThe price, inside the photo frame
    re-listing-card__statusThe status badge, for listings that aren't active
    re-listing-card__bodyThe text below the photo
    re-listing-card__addressThe street address
    re-listing-card__locationCity, state and ZIP
    re-listing-card__specsBeds, baths and square feet
    re-listing-card__courtesy"Courtesy of" the listing brokerage

    The price and status sit inside the photo frame, which is position: relative, so you can place them over the photo:

    .re-listing-card__price {
      position: absolute;
      left: 0.75rem;
      bottom: 0.75rem;
      padding: 0.25rem 0.6rem;
      border-radius: 999px;
      background: rgba(0, 0, 0, 0.7);
      color: #fff;
      font-weight: 600;
    }

    ListingDetail

    ClassElement
    re-listing-detailThe <article>
    re-listing-detail__galleryThe photo strip
    re-listing-detail__imageEach photo in the strip
    re-listing-detail__headerThe header
    re-listing-detail__addressThe <h1>
    re-listing-detail__locationCity, state and ZIP
    re-listing-detail__priceThe price
    re-listing-detail__specsBeds, baths and square feet
    re-listing-detail__factsThe facts <dl>
    re-listing-detail__factEach fact (a <div> holding a <dt> and <dd>)
    re-listing-detail__descriptionThe description
    re-listing-detail__attributionThe "Listed by" line

    ListingGallery

    ClassElement
    re-galleryThe gallery (focusable, for arrow keys)
    re-gallery__mainThe main photo frame
    re-gallery__imageThe main photo
    re-gallery__prev, re-gallery__nextThe previous and next buttons
    re-gallery__countThe "3 / 18" counter
    re-gallery__thumbsThe thumbnail strip
    re-gallery__thumbEach thumbnail button
    re-gallery__thumb--activeThe current thumbnail

    ListingFilters

    ClassElement
    re-listing-filtersThe <form>
    re-listing-filters__fieldEach <label> wrapping a field
    re-listing-filters__field--keywordThe search box's label, as well
    re-listing-filters__submitThe submit button

    ListingPagination

    ClassElement
    re-listing-paginationThe <nav>
    re-listing-pagination__prev, re-listing-pagination__nextThe previous and next links
    re-listing-pagination__disabledAdded to either one when it can't go anywhere
    re-listing-pagination__status"Page 2 of 9 (104 listings)"

    IdxAttribution and ListingInquiryForm

    ClassElement
    re-idx-attributionThe attribution block
    re-idx-attribution__courtesy"Listing courtesy of" line
    re-idx-attribution__updated"MLS data last updated" line
    re-inquiry-formThe <div> around the managed form. The form itself is styled like any site-kit form.

    Overriding inline styles

    A handful of layout essentials are inline styles, so the components look reasonable before you've written any CSS:

    ElementInline styles
    re-listing-griddisplay: grid, 320px minimum columns, gap: 1.5rem
    re-listing-card__linkdisplay: block, inherited color, no underline
    re-listing-card__media16:10 aspect ratio, overflow: hidden, gray background, position: relative
    re-listing-card__image, re-gallery__imageFill the frame with object-fit: cover
    re-listing-card__courtesySmaller font, 0.7 opacity, small top margin
    re-listing-detail__galleryResponsive grid of 280px minimum columns
    re-listing-detail__image4:3 aspect ratio, object-fit: cover
    re-listing-detail__attributionSmaller font, 0.7 opacity
    re-gallery__main16:10 aspect ratio, gray background
    re-gallery__prev, re-gallery__next, re-gallery__count, thumbnailsRound dark buttons and counter, thumbnail sizing
    re-gallery__thumboutline-offset: -2px, so the focus ring draws inside the thumbnail where the scrolling strip can't clip it
    re-listing-filters and its fieldsFlex row that wraps, small labels stacked over inputs
    re-listing-paginationCentered flex row
    re-idx-attributionSmaller font, 0.75 opacity

    The kit never uses !important, so everything else is yours. Inline styles do win over class rules, though, so to change one of the properties above, either mark your rule !important:

    .re-listing-grid {
      grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)) !important;
    }

    or skip the component that sets it. For a different grid, map ListingCard inside your own container (see Cards and grids).

    Focus styles

    The gallery takes keyboard focus so the arrow keys work. It shows the browser's own focus ring when it's focused from the keyboard, and not after a mouse click. The kit doesn't set an outline on it, so a plain class rule restyles the ring, no !important needed:

    .re-gallery:focus-visible {
      outline: 3px solid #2563eb;
      outline-offset: 4px;
      border-radius: 0.5rem;
    }

    Keep a visible style there, and on the gallery's buttons and thumbnails, so keyboard users can always see where they are. Don't set outline: none without a replacement.

    Performance

    Listing pages should render on the server and paint fast on a phone. The kit is built for that; these are the things to keep in mind.

    • Almost everything renders on the server. The root and /server entry points ship no client JavaScript. A listing page's only client code is the gallery, the inquiry form and the view tracker (which renders nothing).
    • Keep the tracker a childless sibling. ListingViewTracker returns null and never wraps content. Don't put page content inside it, or inside any provider: wrapping the page in a client component turns a prerendered page into a client-rendered one.
    • Pass client components only what they read. Props sent to ListingGallery and ListingInquiryForm travel to the browser with the page. Give the form its four listing fields, not the whole listing (see Inquiry forms).
    • Photos are plain <img> tags from the MLS's image host. Cards and thumbnails load lazily. ListingDetail loads its first photo eagerly and the rest lazily, and the gallery's main photo loads eagerly.
    • Don't animate the first photo in. The top photo is usually the largest thing on screen when the page loads. Leave it visible from the first paint, with no fade or slide-in, and save entrance animations for content further down.
    • Check the HTML. After a build, curl a listing page and confirm the address, price and card markup are in the response. If you only see a script payload, something above the listing content has become a client component.