Search code examples
javascriptnpmtailwind-cssastrojs

Custom Fragments in AstroJS


Currently, starting to learn AstroJS. I was looking into the templates from github and I found this <Fragment> tag and referred astro documentation and that says it can be used for directives. I've provided the code below for reference.

    <Fragment slot="title">
      Free template for <span class="hidden xl:inline">creating websites with</span>
      <span class="text-accent dark:text-white highlight"> Astro 4.0</span> + Tailwind CSS
    </Fragment>

Here I see a parameter as slot. So I tried to see the definition of the Fragment and got into this file env.d.ts

/// <reference path="./client.d.ts" />

// Caution! The types here are only available inside Astro files (injected automatically by our language server)
// As such, if the typings you're trying to add should be available inside ex: React components, they should instead
// be inside `client.d.ts`

type Astro = import('./dist/@types/astro.js').AstroGlobal;

// We have to duplicate the description here because editors won't show the JSDoc comment from the imported type
// However, they will for its properties, ex: Astro.request will show the AstroGlobal.request description
/**
 * Astro global available in all contexts in .astro files
 *
 * [Astro documentation](https://docs.astro.build/en/reference/api-reference/#astro-global)
 */
declare const Astro: Readonly<Astro>;

declare const Fragment: any;

declare module '*.html' {
    const Component: (opts?: { slots?: Record<string, string> }) => string;
    export default Component;
}

Here I don't see any slot parameter but how come this is working. Currently the slot is title and the font is also big but if it's subtitle the font size reduces. I also don't see any declaration from tailwind with title. I have provided tailwind.config.cjs file

import defaultTheme from 'tailwindcss/defaultTheme';
import typographyPlugin from '@tailwindcss/typography';

module.exports = {
  content: ['./src/**/*.{astro,html,js,jsx,json,md,mdx,svelte,ts,tsx,vue}'],
  theme: {
    extend: {
      colors: {
        primary: 'var(--aw-color-primary)',
        secondary: 'var(--aw-color-secondary)',
        accent: 'var(--aw-color-accent)',
        default: 'var(--aw-color-text-default)',
        muted: 'var(--aw-color-text-muted)',
      },
      fontFamily: {
        sans: ['var(--aw-font-sans, ui-sans-serif)', ...defaultTheme.fontFamily.sans],
        serif: ['var(--aw-font-serif, ui-serif)', ...defaultTheme.fontFamily.serif],
        heading: ['var(--aw-font-heading, ui-sans-serif)', ...defaultTheme.fontFamily.sans],
      },
    },
  },
  plugins: [typographyPlugin],
  darkMode: 'class',
};

Can someone please explain this? Also provided the repo link


Solution

  • The slot attribute on the Fragment component specifies which slot Fragment should render within the Hero component.

    If we take a look at the Hero component, we see:

    const {
      id,
      title = await Astro.slots.render('title'),
      subtitle = await Astro.slots.render('subtitle'),
      tagline,
      content = await Astro.slots.render('content'),
      actions = await Astro.slots.render('actions'),
      image = await Astro.slots.render('image'),
    } = Astro.props;
    
    ---
    …
    
    {
      title && (
        <h1
          class="text-5xl md:text-6xl font-bold leading-tighter tracking-tighter mb-4 font-heading dark:text-gray-200"
          set:html={title}
        />
      )
    }
    <div class="max-w-3xl mx-auto">
      {subtitle && <p class="text-xl text-muted mb-6 dark:text-slate-300" set:html={subtitle} />}
    

    So if we have slot="title", we would see:

    <h1
      class="text-5xl md:text-6xl font-bold leading-tighter tracking-tighter mb-4 font-heading dark:text-gray-200"
    >
      Free template for <span class="hidden xl:inline">creating websites with</span>
      <span class="text-accent dark:text-white highlight"> Astro 4.0</span> + Tailwind CSS
    </h1>
    

    Whereas if we have slot="subtitle", we would see:

    <p class="text-xl text-muted mb-6 dark:text-slate-300">
      Free template for <span class="hidden xl:inline">creating websites with</span>
      <span class="text-accent dark:text-white highlight"> Astro 4.0</span> + Tailwind CSS
    <p>
    

    So, the text is bigger for slot="title" because the elements inside the Fragment is rendered inside a HTML tag that specifies a larger font size with text-5xl md:text-6xl. Whereas for slot="title", the elements would be rendered inside a HTML tag that has text-xl, which is a smaller font size.